Skip to main content

Forms and Components

11 replies [Last post]
kawaiimomo
Offline
Joined: 2008-07-10
Points: 0

Hello all there,

I'm having some strange issues which make me think about how Forms an Components are related.

I have something similar to this:

<br />
import javax.microedition.midlet.MIDlet;<br />
import javax.microedition.midlet.MIDletStateChangeException;</p>
<p>import com.sun.lwuit.Command;<br />
import com.sun.lwuit.Display;<br />
import com.sun.lwuit.Form;<br />
import com.sun.lwuit.Label;<br />
import com.sun.lwuit.events.ActionEvent;<br />
import com.sun.lwuit.events.ActionListener;</p>
<p>public class Testing extends MIDlet implements ActionListener {</p>
<p>	protected void startApp() throws MIDletStateChangeException {<br />
		Display.init(this);<br />
		showFirstScreen();<br />
	}</p>
<p>	Label label = new Label("Hey There");<br />
	public void showFirstScreen() {<br />
		Form form = new Form() {<br />
			public void keyPressed(int keyCode) {<br />
				showSecondScreen();<br />
			}<br />
		};</p>
<p>		form.addComponent(label);</p>
<p>		form.show();<br />
	}</p>
<p>	public void showSecondScreen() {<br />
		Form form = new Form() {<br />
			public void keyPressed(int keyCode) {<br />
				showFirstScreen();<br />
			}<br />
		};</p>
<p>		form.addCommand(new Command("back", 0));<br />
		form.setCommandListener(this);<br />
		form.addComponent(new Label("2nd screen"));</p>
<p>		form.show();<br />
	}</p>
<p>	public void actionPerformed(ActionEvent event) {<br />
		switch (event.getCommand().getId()) {<br />
		case 0:<br />
			showFirstScreen();<br />
			break;<br />
		}<br />
	}</p>
<p>	protected void destroyApp(boolean arg0) throws MIDletStateChangeException {<br />
	}</p>
<p>	protected void pauseApp() {<br />
	}<br />
}<br />

The thing is, the Label in first screen is a global variable. When I click any key, I swicth to second screen. From there, if I press back Command first screen is created again.

Why it says that the Component (Label) is already in the Container if the Container is a local variable. When will it be out of scope then?

In other words: I have a global Component and want to add to a local form. Probably later i will be adding the same Component to same but new instatiated local form. Is there anything I'm missing? How to release the Component from the Container? I thought setting the Container to null would do the trick, but no. In fact if I ask the newly created Form if he has the global Label Component, he returns a -1 (getComponentIndex(Component)) indicating the Component is not associated to the Form (sure, it's a new instance), but anyway I can't addComponent() if I don't remove it first.

Any advice, please?

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Francis De Brabandere

On Fri, Jul 18, 2008 at 8:02 AM, Shai Almog wrote:
> Hi Claes,
> garbage collection works the same as in Java SE for Java ME.
> Garbage management works the same for LWUIT as it does for Swing.
> Since a component in LWUIT has a reference to its parent, if the component
> won't be collected neither would its parent all the way up to the containing
> form.

I don't get this one, won't the class member Components + the form be
garbage collected when the form is not accessible any more? Shouldn't
this sentence be the other way round: "If the form won't be collected
neither would its member Components"?

--
http://www.somatik.be
Microsoft gives you windows, Linux gives you the whole house.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@lwuit.dev.java.net
For additional commands, e-mail: users-help@lwuit.dev.java.net

Shai Almog

>> Hi Claes,
>> garbage collection works the same as in Java SE for Java ME.
>> Garbage management works the same for LWUIT as it does for Swing.
>> Since a component in LWUIT has a reference to its parent, if the
>> component
>> won't be collected neither would its parent all the way up to the
>> containing
>> form.
>
> I don't get this one, won't the class member Components + the form be
> garbage collected when the form is not accessible any more? Shouldn't
> this sentence be the other way round: "If the form won't be collected
> neither would its member Components"?

Hi Francis,
There are no more references to the form but there are references to
the component consider this:

private Button myButton;

private void calledOnStartup() {
Form myForm = new Form(....);
myButton = new Button(...);
myForm.addComponent(myButton);
myButton.addActionListener(...);
myForm.show();
}

private void calledOnButtonPress() {
new Form("Empty").show();
}

After pressing the button myForm is no longer reachable from
Display.getInstance().getCurrent() and thus is supposedly ready for
GC (garbage).
However, it is reachable by invoking:
myButton.getParent().getParent();

(first getParent() will return the content pane).
This essentially prevents the garbage collector from reclaiming it
because the component is still reachable in the class scope.

Thanks.

Shai Almog
http://lwuit.blogspot.com/

[att1.html]

Francis De Brabandere

Now I see how you get there, I'm always extending forms in my
application so the components are always member of the form and not
some other class.

class BlaForm extends Form{
private Button myButton;
....
}

Is this a bad design form mobile dev?

On Fri, Jul 18, 2008 at 10:09 AM, Shai Almog wrote:
>
> Hi Claes,
> garbage collection works the same as in Java SE for Java ME.
> Garbage management works the same for LWUIT as it does for Swing.
> Since a component in LWUIT has a reference to its parent, if the component
> won't be collected neither would its parent all the way up to the containing
> form.
>
> I don't get this one, won't the class member Components + the form be
> garbage collected when the form is not accessible any more? Shouldn't
> this sentence be the other way round: "If the form won't be collected
> neither would its member Components"?
>
> Hi Francis,
> There are no more references to the form but there are references to the
> component consider this:
> private Button myButton;
> private void calledOnStartup() {
> Form myForm = new Form(....);
> myButton = new Button(...);
> myForm.addComponent(myButton);
> myButton.addActionListener(...);
> myForm.show();
> }
> private void calledOnButtonPress() {
> new Form("Empty").show();
> }
>
> After pressing the button myForm is no longer reachable from
> Display.getInstance().getCurrent() and thus is supposedly ready for GC
> (garbage).
> However, it is reachable by invoking:
> myButton.getParent().getParent();
> (first getParent() will return the content pane).
> This essentially prevents the garbage collector from reclaiming it because
> the component is still reachable in the class scope.
> Thanks.
> Shai Almog
> http://lwuit.blogspot.com/
>

--
http://www.somatik.be
Microsoft gives you windows, Linux gives you the whole house.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@lwuit.dev.java.net
For additional commands, e-mail: users-help@lwuit.dev.java.net

Shai Almog

If you extend form this shouldn't be a problem since the reference to
myButton will be gone when you show() the next form. So this
shouldn't be a problem.

Thanks,
Shai.

> Now I see how you get there, I'm always extending forms in my
> application so the components are always member of the form and not
> some other class.
>
> class BlaForm extends Form{
> private Button myButton;
> ....
> }
>
> Is this a bad design form mobile dev?
>
> On Fri, Jul 18, 2008 at 10:09 AM, Shai Almog
> wrote:
>>
>> Hi Claes,
>> garbage collection works the same as in Java SE for Java ME.
>> Garbage management works the same for LWUIT as it does for Swing.
>> Since a component in LWUIT has a reference to its parent, if the
>> component
>> won't be collected neither would its parent all the way up to the
>> containing
>> form.
>>
>> I don't get this one, won't the class member Components + the form be
>> garbage collected when the form is not accessible any more? Shouldn't
>> this sentence be the other way round: "If the form won't be collected
>> neither would its member Components"?
>>
>> Hi Francis,
>> There are no more references to the form but there are references
>> to the
>> component consider this:
>> private Button myButton;
>> private void calledOnStartup() {
>> Form myForm = new Form(....);
>> myButton = new Button(...);
>> myForm.addComponent(myButton);
>> myButton.addActionListener(...);
>> myForm.show();
>> }
>> private void calledOnButtonPress() {
>> new Form("Empty").show();
>> }
>>
>> After pressing the button myForm is no longer reachable from
>> Display.getInstance().getCurrent() and thus is supposedly ready
>> for GC
>> (garbage).
>> However, it is reachable by invoking:
>> myButton.getParent().getParent();
>> (first getParent() will return the content pane).
>> This essentially prevents the garbage collector from reclaiming it
>> because
>> the component is still reachable in the class scope.
>> Thanks.
>> Shai Almog
>> http://lwuit.blogspot.com/
>>
>
>
>
> --
> http://www.somatik.be
> Microsoft gives you windows, Linux gives you the whole house.
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@lwuit.dev.java.net
> For additional commands, e-mail: users-help@lwuit.dev.java.net
>

Shai Almog
http://lwuit.blogspot.com/

[att1.html]

cinsulan
Offline
Joined: 2008-04-19
Points: 0

Shai,

Great work and thanks! Your last explanation explains why I misunderstood the initial explanation. I also only extend forms and keep members within the form making the form reference crucial for GC, but not the components. I almost thought I had a mem leak...

Shai Almog

Hi Kawaiimomo,
In a component tree type widget system such as Swing/AWT, LWUIT
etc... every component has a pointer to its parent which you can
access using Component.getParent().

Since this is the case the previous form was never garbage collected
although it was out of scope so the label wasn't removed. Java (and
LWUIT) has no way of detecting that the Form is no longer used by
yourself. We generally recommend to avoid components as class members
and make sure to set them to null when leaving the scope (as we
practice in the LWUIT Demo).

Thanks,
Shai.

> Hello all there,
>
> I'm having some strange issues which make me think about how Forms
> an Components are related.
>
> I have something similar to this:
>
> [code]
> import javax.microedition.midlet.MIDlet;
> import javax.microedition.midlet.MIDletStateChangeException;
>
> import com.sun.lwuit.Command;
> import com.sun.lwuit.Display;
> import com.sun.lwuit.Form;
> import com.sun.lwuit.Label;
> import com.sun.lwuit.events.ActionEvent;
> import com.sun.lwuit.events.ActionListener;
>
> public class Testing extends MIDlet implements ActionListener {
>
> protected void startApp() throws MIDletStateChangeException {
> Display.init(this);
> showFirstScreen();
> }
>
>
> Label label = new Label("Hey There");
> public void showFirstScreen() {
> Form form = new Form() {
> public void keyPressed(int keyCode) {
> showSecondScreen();
> }
> };
>
> form.addComponent(label);
>
> form.show();
> }
>
> public void showSecondScreen() {
> Form form = new Form() {
> public void keyPressed(int keyCode) {
> showFirstScreen();
> }
> };
>
> form.addCommand(new Command("back", 0));
> form.setCommandListener(this);
> form.addComponent(new Label("2nd screen"));
>
> form.show();
> }
>
> public void actionPerformed(ActionEvent event) {
> switch (event.getCommand().getId()) {
> case 0:
> showFirstScreen();
> break;
> }
> }
>
> protected void destroyApp(boolean arg0) throws
> MIDletStateChangeException {
> }
>
> protected void pauseApp() {
> }
> }
> [/code]
>
> The thing is, the Label in first screen is a global variable. When
> I click any key, I swicth to second screen. From there, if I press
> back Command first screen is created again.
>
> Why it says that the Component (Label) is already in the Container
> if the Container is a local variable. When will it be out of scope
> then?
>
> In other words: I have a global Component and want to add to a
> local form. Probably later i will be adding the same Component to
> same but new instatiated local form. Is there anything I'm missing?
> How to release the Component from the Container? I thought setting
> the Container to null would do the trick, but no. In fact if I ask
> the newly created Form if he has the global Label Component, he
> returns a -1 (getComponentIndex(Component)) indicating the
> Component is not associated to the Form (sure, it's a new
> instance), but anyway I can't addComponent() if I don't remove it
> first.
>
> Any advice, please?
> [Message sent by forum member 'kawaiimomo' (kawaiimomo)]
>
> http://forums.java.net/jive/thread.jspa?messageID=287305
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@lwuit.dev.java.net
> For additional commands, e-mail: users-help@lwuit.dev.java.net
>

Shai Almog
http://lwuit.blogspot.com/

[att1.html]

cinsulan
Offline
Joined: 2008-04-19
Points: 0

Shai,

I find this statement somewhat peculiar.

"We generally recommend to avoid components as class members
and make sure to set them to null when leaving the scope (as we
practice in the LWUIT Demo)."

Are you saying that you consider having components as class members is bad practice or just "be careful" when you do so?

Edit: Isn't the above example an extreme because the label is actually member of he Midlet and not a separate form?

Having components as class members is most convenient when having to set their values at regular intervals. Of course, one could create runnables as members and use them together with member variables to updated their values, but it would be messy code in my opinion.

I assume the garbage collection works the same way as in j2se i.e. from the root component, if there are no references to another component, it will be removed. I have a form manager that keeps track of all forms using a hashtable for references. Assuming that is the only reference to a form, removing it should allow that form to be garbage collected, no?

Thankful for a reply.

Claes

Message was edited by: cinsulan

Message was edited by: cinsulan

Shai Almog

Hi Claes,
garbage collection works the same as in Java SE for Java ME.
Garbage management works the same for LWUIT as it does for Swing.

Since a component in LWUIT has a reference to its parent, if the
component won't be collected neither would its parent all the way up
to the containing form.

This is easy to solve by one of the following strategies:

1. Rather than keep a class member keep a final variable for inner
classes:
void myMethod() {
final Button b = new Button(...);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
// do something with b
}
});
}

in this case the button will be collected as you would expect.

2. When leaving the form/dialog just set component members to null to
remove their reference. Recreate them as necessary:
public void actionPerformed(ActionEvent ev) {
// navigating out of screen
componentUsedInScreen =null;
}

3. Remove component from parent when navigating outside of the screen:
public void actionPerformed(ActionEvent ev) {
// navigating out of screen
if(componentUsedInScreen != null) {
componentUsedInScreen.getParent().removeComponent
(componentUsedInScreen);
}
}

4. Rely on the source value of the action performed method (won't
work for commands):
void myMethod() {
List l = new List(...);
l.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
List l = (List)ev.getSource();
// do something with l
}
});
}

We use the first approach where possible in the LWUIT demo and
sometimes the 3rd/2nd approach (depending on the case). This is
essential for smaller and memory limited devices that we GC as much
as possible, recreating a form/component is relatively cheap!

I also blogged a bit about memory issue tracking here:
http://lwuit.blogspot.com/2008/06/memory-leaks-in-lwuit-and-
tracking.html

> "We generally recommend to avoid components as class members
> and make sure to set them to null when leaving the scope (as we
> practice in the LWUIT Demo)."
>
> Are you saying that you consider this bad practice or just "be
> careful"?

Like I said we keep a reference in the class member ourselves see the
LWUIT Demo's RenderingDemo.cleanup() code to see what I mean. The bad
practice is not cleaning up when you leave a form, the GC is powerful
but if you keep a reference to something it just can't remove it.

> Having components as class members is most convenient when having
> to set their values at regular intervals. Of course, one could
> create runnables as members and use them together with member
> variables to updated their values, but it would be messy code in my
> opinion.

Sure but you don't need a reference to them when they are not on the
screen. You could afford this "wastefulness" in Swing (which also has
the exact same behavior) but you can't afford it in a S40 device.

Thanks,

Shai Almog
http://lwuit.blogspot.com/

[att1.html]

kawaiimomo
Offline
Joined: 2008-07-10
Points: 0

Hi,

Thanks a lot for the nice explanation and the info :-)

In my case, the class member is a MediaComponent and it's very likely the user would return again to that screen many times, so I thought it was better in terms of memory to declare it global and only initialize the player and create the MediaComponent only once.

Do you think is better this way and removing the reference to its parent when leaving the Form, or better create a new final instance of MediaComponent every time the user goes to that screen?

The problem I found in this final variable approach is that everytime the method is called it needs to create a new instance of a Player in order to be able to create a new MediaComponent(myPlayer), because creating the MediaComponent implies inner calls to Player.initDisplayMode and so on and this ends with an Exception saying it has been already initialized. Besides all this, the Player instance should be final too in order to be able to call Player.stop() when leaving the screen.

I guess creating new instances everytime the user wants to take a snapshot derives in high memory usage. In the other hand I only need to keep 2 global instances. So what do you guys recommend in this scenario?

Best Regards.

PS: Sorry if I went a little off topic ;-)

Shai Almog

Hi,
> In my case, the class member is a MediaComponent and it's very
> likely the user would return again to that screen many times, so I
> thought it was better in terms of memory to declare it global and
> only initialize the player and create the MediaComponent only once.

Chen is a bigger expert than myself in the media dept. so he might be
able to contribute a better strategy here.
AFAIK you are correct, realizing a media file might be lengthy so it
might be a good idea to cache the component. So the strategy of
removing it from the parent component (thus allowing the form to GC)
might be better.
It might also be OK to leave this form always and never recreate
it... We do this in LWUIT demo for the home screen which contains
many icons in 3 different states, so we just keep the form always in
memory and avoid the penalty of recreating it (while paying in memory
overhead).

> I guess creating new instances everytime the user wants to take a
> snapshot derives in high memory usage. In the other hand I only
> need to keep 2 global instances. So what do you guys recommend in
> this scenario?

If you have only one such form it might be reasonable to keep it in
memory. I would run on the S40 emulator (enable its memory diagnosis
option) and see the overhead, if you can work there then you are in
reasonably good shape.

> PS: Sorry if I went a little off topic ;-)

This is not off topic!! ;-)

Thanks.
Shai Almog
http://lwuit.blogspot.com/

[att1.html]

kawaiimomo
Offline
Joined: 2008-07-10
Points: 0

Thanks again Shai, for the good work and kind responses. Really appreciated.

I'm trying with creating new instances everytime and works well in terms of memory and speed. But you are right, it's a better idea to keep the whole form in memory.

Many Thanks!