Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EGL Development Tools » How can I manage widget instances?
How can I manage widget instances? [message #878754] Tue, 29 May 2012 17:34 Go to next message
Richard Moulton is currently offline Richard Moulton
Messages: 92
Registered: August 2011
Location: Devon, UK
Member
I've been working on a small application written using EDT 0.8M1 and noticed some unexpected behaviour.

I often use the following method to create new child widgets:

ui.children = [ new Box{ height=100, width=100, backgroundColor="Red" } ];

If I repeat this statement a number of times I've found that the previous instances of the Box widget (in this example) continue to exist. I noticed this because of some InfoBus broadcasts I was using to communicate between widgets.

I can see the dilemma ... when should that box widget be destroyed. But in my example I believe that as soon as I execute the same statement, replacing the children in the ui widget, I have no way of referencing the first Box widget instance.

Is this behaviour expected?

Is there a way of managing widget instances?

Richard
Re: How can I manage widget instances? [message #879760 is a reply to message #878754] Thu, 31 May 2012 15:44 Go to previous messageGo to next message
Justin Spadea is currently offline Justin Spadea
Messages: 66
Registered: July 2009
Member
Hi Richard,

I've asked if someone with more expertise in the widgets can take a look at this. Stay tuned...

-Justin
icon6.gif  Re: How can I manage widget instances? [message #881302 is a reply to message #878754] Mon, 04 June 2012 06:03 Go to previous messageGo to next message
lu lu is currently offline lu lu
Messages: 9
Registered: June 2012
Junior Member
Hi Sorry for the late response.

I investigate the Destory widget process in Gridlayout.

If you always use
ui.children = {new Box{..}} without located in any cell of GridLayout?

In initTable() method, children of table will be destoryed, I write a sample, not sure if what you required.

1. 'Button' & 'Box' are the children of ui.
2. When click 'Button', then the children of gridLayout will be 'change' widget only.

**************************************************
package client;

// RUI Handler

import org.eclipse.edt.rui.widgets.Box;
import org.eclipse.edt.rui.widgets.GridLayout;
import org.eclipse.edt.rui.widgets.GridLayoutData;
import org.eclipse.edt.rui.widgets.Button;
import dojo.widgets.DojoButton;

//
//

handler bb type RUIhandler{initialUI =[ui
], onConstructionFunction = start, cssFile = "css/v.css", title = ""}

ui GridLayout{columns = 3, rows = 4, cellPadding = 4, children = [ Button, Box ]};
Box Box{ layoutData = new GridLayoutData{ row = 3, column = 2 }, padding=8 };
change Button{ layoutData = new GridLayoutData{ row = 4, column = 2 }, text="Normal Button, Children of GridLayout" };
Button DojoButton{ layoutData = new GridLayoutData{ row = 4, column = 2 }, text = "Change Children", onClick ::= Button_onClick };

function start()

end

function Button_onClick(event Event in)
ui.children = [change];
end
end
******************************************************

If this is what you required, pls provide me some of your sample usage. Thanks.
Re: How can I manage widget instances? [message #881348 is a reply to message #881302] Mon, 04 June 2012 07:37 Go to previous messageGo to next message
Richard Moulton is currently offline Richard Moulton
Messages: 92
Registered: August 2011
Location: Devon, UK
Member
Hi,

I didn't fully understand what you were saying but below I've included a sample that illustrates my point/question.

The first source is for a main rui handler. This displays two buttons; one to add a new box child to my main handler, replacing the previous children and the second will publish an infobus request to the widget children asking them to say hello.

The second source is for my widget that will be added as a child of the main handler when the 'add box' button is pressed.

If you try this and then press the 'add box' n times and then press the 'say hello' button you will get a response from all of the added widgets, so they still exist.

My question revolves around the use of the following code, to add a child. By using this code it appears that I then unable to destroy that child widget.

container.children = [ new TestWidget{ height=100, width=100, backgroundColor=boxColour, children=[ new HTML{ text = "I am box number " :: boxNumber } ], boxNumber=boxNumber } ];

Is there a way I can destroy that child widget?

Is this behaviour expected?

Is there some method I should be using to manage new widget instances?

I hope that makes my question(s) clearer.

Richard


****************************************************

package client;

import org.eclipse.edt.rui.infobus.InfoBus;
import org.eclipse.edt.rui.widgets.Button;
import org.eclipse.edt.rui.widgets.Div;
import org.eclipse.edt.rui.widgets.HTML;

handler TestParent type RUIhandler{initialUI =[ui], onConstructionFunction = start, cssFile = "css/stocks.css", title = "TestParent"}

ui Div{children =[addboxButton, sayhiButton, container]};
container Div{ children=[] };
addboxButton Button{ text="Add Box",onClick::=addBox };
sayhiButton Button{ text="Say Hello",onClick::=sayHi };
boxNumber int = 0;

function start()
end

function addBox(e event in)

boxNumber += 1;
boxColour string;

case(boxNumber%3)
when(1)
boxColour = "Red";
when(2)
boxColour = "Blue";
otherwise
boxColour = "yellow";
end

container.removeChildren();
container.children = [
new TestWidget{ height=100, width=100, backgroundColor=boxColour,
children=[ new HTML{ text = "I am box number " :: boxNumber } ],
boxNumber=boxNumber } ];

end

function sayHi(e event in)
InfoBus.publish("SayHello", "Hello from box number ");
end

end

****************************************************

package client;

import org.eclipse.edt.rui.infobus.InfoBus;
import org.eclipse.edt.rui.widgets.Div;

handler TestWidget type RUIWidget{targetWidget = ui, onConstructionFunction = start, cssFile = "css/stocks.css", @VEWidget{category = "Custom"}}

ui Div{ children = [container] };
container Div{ children = [] };
boxNumber int;

function start()
InfoBus.subscribe("SayHello", SayHello_callback);
end

function setChildren(widgets widget[] in)
container.children = widgets;
end

function SayHello_callback(eventName string in, data any in)
sysLib.writeStdout(data as string :: boxNumber);
end

end


****************************************************

Re: How can I manage widget instances? [message #882097 is a reply to message #881348] Tue, 05 June 2012 17:01 Go to previous messageGo to next message
Brian Svihovec is currently offline Brian Svihovec
Messages: 55
Registered: July 2009
Member
Richard,

In your example, both the TestParent handler and the InfoBus Library are holding a pointer to your TestWidget handler, with TestParent holding a direct pointer to the TestWidget, and InfoBus holding an 'indirect' pointer via the callback function 'SayHello_callback'. When you reset the children of the container div in TestParent.addBox, you are breaking the link from TestParent to TestWidget, but the InfoBus is still holding this link as you have discovered.

In this situation, I believe you will either need to let the TestParent manage the subscribing and unsubscribing of the TestWidget with the InfoBus, or you will need to add a function to TestWidget that you can invoke from TestParent to 'cleanup' the TestWidget when it is no longer needed. Once an object is no longer being referenced by any other objects, the JavaScript garbage collector will automatically reclaim the memory associated with the object.

It is also worth mentioning that in addition to managing the InfoBus subscription, you will also need to tell the Rich UI runtime framework that a widget is no longer needed, so that the DOM elements associated with the widget can be discarded. To do this in your example, I believe you will need to do something like the following:

theChildren Widget[] = container.children;  // hold onto the children 
container.removeChildren();  // remove them from the container

for(i int from 1 to theChildren.getSize())
  UtilLib.destroyWidget(theChildren[i]); // destroy the children
end


Invoking destroyWidget is necessary because some older browsers are unable to reclaim the memory of JavaScript objects that are holding references to the DOM tree, which can cause a memory leak if the browser window is refreshed since all of the widget objects cannot be reclaimed. To work around this issue, the Rich UI Runtime keeps track of all widgets that are created and automatically destroys them when the application is terminated. During the destroy process, all of the DOM elements associated with the widget, and its children, are separated from their corresponding JavaScript objects so that the memory can be reclaimed.

If an application creates and discards widgets as part of its normal processing, these discarded widgets will appear as memory leaks in the runtime until the application is terminated. An alternative to invoking destroy in this situation is to re-use as many widget instances as possible, instead of creating new widgets, but in some cases it may be necessary for a widget to be destroyed using the UtilLib functions.

-Brian
Re: How can I manage widget instances? [message #882434 is a reply to message #882097] Wed, 06 June 2012 09:06 Go to previous messageGo to next message
Richard Moulton is currently offline Richard Moulton
Messages: 92
Registered: August 2011
Location: Devon, UK
Member
Brian,

Many thanks for the info. I'll write some code within my widgets to issue an infobus.unsubscribe when I want to destroy the widget.

Is there someplace that I can see the widgets that have been created within my application? You mention that the rui runtime keeps track of the widgets as they are created. I've had a quick look at the dom using FireBug but I couldn't obviously find my widgets.

Richard
Re: How can I manage widget instances? [message #882465 is a reply to message #882434] Wed, 06 June 2012 10:04 Go to previous messageGo to next message
Brian Svihovec is currently offline Brian Svihovec
Messages: 55
Registered: July 2009
Member
Richard,

Check out egl.elements in FireBug for a list of the widgets being maintained by the runtime.

-Brian
Re: How can I manage widget instances? [message #882578 is a reply to message #882465] Wed, 06 June 2012 15:13 Go to previous messageGo to next message
Richard Moulton is currently offline Richard Moulton
Messages: 92
Registered: August 2011
Location: Devon, UK
Member
Brian,

In addition to egl.elements I also found OpenAjax.hub._subscriptions and when I unsubscribe I can see the subscriptions disappear from this section but the widgets still remain within the egl.elements section.

Does that mean that there is still some link that is stopping these objects from being destroyed?

How can I tell whether there is a link to these objects that is stopping them from being destroyed?

I haven't tried the destroyWidget function yet as I've tested this on the latest versions of both Firefox and Chrome.

Richard
Re: How can I manage widget instances? [message #883056 is a reply to message #882578] Thu, 07 June 2012 14:53 Go to previous messageGo to next message
Brian Svihovec is currently offline Brian Svihovec
Messages: 55
Registered: July 2009
Member
Richard,

OpenAjax.hub._subscriptions maintains the subscriptions that you are manually defining in your application when using InfoBus.subscribe(), and it is important that you unsubscribe any widgets that you are no longer using so that they can be garbage collected.

Any elements that you create are also automatically added to the egl.elements array by the Rich UI runtime when they are created, and are only removed from this array when the application is terminated or when UtilLib.destroyWidget() is invoked.

In general, a widget can only be garbage collected by the browser when it is no longer being referenced by the application. All widgets that are no longer being used should be destroyed using UtilLib.destoryWidget(), but before destoryWidget is invoked, "manual" references to these widgets should also be removed from the application, which could include InfoBus subscriptions, storage in an array of another widget or handler, etc.

In the future, it would be best if the Rich UI Runtime can be updated to automatically invoke destroyWidget on elements of the array that are no longer being referenced by an application, but for now this has to be invoked manually.

-Brian
Re: How can I manage widget instances? [message #883394 is a reply to message #883056] Fri, 08 June 2012 08:43 Go to previous messageGo to next message
Richard Moulton is currently offline Richard Moulton
Messages: 92
Registered: August 2011
Location: Devon, UK
Member
Brian,

Thanks for your help and the information you've provided.

I'll have a go at implementing the destroyWidget function within my widgets and execute this when I know I've finished with the widget, possibly building a destroyChildren function that performs similar steps to those you outlined.

However, would the following code also destroy the children of theChildren? I'll test this.

for(i int from 1 to theChildren.getSize())
  UtilLib.destroyWidget(theChildren[i]); // destroy the children
end


Many Thanks
Richard
Re: How can I manage widget instances? [message #984566 is a reply to message #883394] Wed, 14 November 2012 15:16 Go to previous message
Richard Moulton is currently offline Richard Moulton
Messages: 92
Registered: August 2011
Location: Devon, UK
Member
An update of my garbage collection experience to date has been posted on the RBD EGL forum...

https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14908648&#14908648

Richard
Previous Topic:New Record From DB Generates Warning
Next Topic:Tomcat 7 Eror in IDE
Goto Forum:
  


Current Time: Sat Aug 23 16:01:58 EDT 2014

Powered by FUDForum. Page generated in 0.01995 seconds