Reloading a component but maintaining the same instance in Flex - apache-flex

Let's say that I have a canvas component called myCanvas and I instantiated it with
var myCanvasPage:myCanvas = new myCanvas;
this.addChild(myCanvasPage);
Then I want to essentially reload myCanvasPage later on. In effect I want to do this:
this.removeChild(myCanvasPage);
var myCanvasPage:myCanvas = new myCanvas;
this.addChild(myCanvasPage);
except instead of creating a new instance of myCanvas, I want to use the already created instance of myCanvas and essentially reload or re-create it but making sure that the instance name and references to it remain the same. What would be the best way to do this?

Whenever you do
var myCanvasPage:myCanvas = new myCanvas;
you are instantiating the myCanvasPage Object.
Removing an object from the stage will not delete the Object from memory.
As long as there is a reference somewhere in your code the myCanvasPage Object will not be garbage collected and all the values and attributes will be the same as at the time you removed it from the stage.
To make that reference you have to scope it to your class.
public var myCanvasPage:myCanvas = new myCanvas;
So now you would reference it with
this.myCanvasPage
and when you are ready to add it back to the stage.
this.addChild(this.myCanvasPage);
So to recap you can add and remove an Object from stage
this.addChild(this.myCanvasPage);
this.removeChild(this.myCanvasPage);
all day long and the data in that object will never go away.
Some good reading on garbage collection

What do you mean as "reloading"? Maybe it is simpler to create data-driven components and change that data to change or reset component state>

Woa I'm not sure where to start here... I think THE_asMan addresses most of your misunderstandings. The missing bit I think you need to look into is how a reference to an object holds (i.e. is counted) as long as it doesn't go out of scope. Just keep in mind that as long as the a variable is not out of scope, its reference to some object (if there is one, i.e. if it is not null) is counted.
http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f9d.html#WS5b3ccc516d4fbf351e63e3d118a9b90204-7f8c

Related

Is there any difference of reset an ArrayCollection by set it's source or change it's reference

I have two ArrayCollection now (a, b) and a is set bindable. I want to reset a with b.
The old code in our project is like:
a = new ArrayCollection();
for (var i:int = 0; i < b.length; i++) {
a.addItem(b.getItemAt(i));
}
Then, I think it may cause a potential memory leak. So I changed it to:
a.removeAll();
for (var i:int = 0; i < b.length; i++) {
a.addItem(b.getItemAt(i));
}
Then I read a topic: Flex optimization tip: ArrayCollection.removeAll() vs. ArrayCollection.source = new Array(). Is this a bug ?
It says removeAll() will cause a performance problem when the data set is large.
So does it means there is a trick off? If the data set is small I should use removeAll, and if the data set is large, I should not use removeAll()?
Another question, I also read a topic about Changing the source of an ArrayCollection.
It says if directly use a = b, "it will kill all the databound controls that are listening to events on the ArrayCollection instance". I don't understand this. I tried a = b, and it works ok (the view that use a as dataprovider updates).
What's the difference between using a=b and a.source = b.source?
I'm new to Flex. Thanks in advance.
ArrayCollection is a wrapper class around Array, and underlying Array can be access using source property
The ArrayCollection class is a wrapper class that exposes an Array as
a collection that can be accessed and manipulated using the methods
and properties of the ICollectionView or IList interfaces. Operations
on a ArrayCollection instance modify the data source; for xample, if
you use the removeItemAt() method on an ArrayCollection, you remove
the item from the underlying Array.
so one should always use Source property of ArrayCollection, if have populated Array
i suggest to declare b as Array not as ArrayCollection and initialize a as
a = new ArrayCollection(b); or
a= new ArrayCollection();// Default constructor ArrayCollection(source:Array=null);
a.source = b; //updates data in Arraycollection
Data Binding means bound controls with datasource(could be any thing like functions, objects, other control, Array, XML, Collection, List etc)
Data binding is the process of tying the data in one object to another
object. It provides a convenient way to pass data between the
different layers of the application. Data binding requires a source
property, a destination property, and a triggering event that
indicates when to copy the data from the source to the destination. An
object dispatches the triggering event when the source property
changes.
Data Binding could be harmful for application with large data because it would creates multiple changes events and both getter and setter executes on change, which need extra proccessing so it would be good practice to shorter scope of a and provide data directly to source as
private function handler_B_DataChange(event:Event)
{
var a:Arraycollection = new ArrayCollection(b);
controlA.dataProvider = a;
//or just
controlB.dataProvider = new ArrayCollection(b);
}
Details of binding could be view on Binding to functions, Objects, and Arrays
Hopes that Helps
I would also try:
a.removeAll();
a.addAll(b.list);
When you declare:
a = new ArrayCollection()
it loses the pointer to the "old" ArrayCollection where it is binded to your application. Thus, that is why when you do "new ArrayCollection" the binding doesn't work anymore. However, in your example, you're not creating a "new ArrayCollection"... you're just replacing the objects in that ArrayCollection with something else... So the binding still works.
If you have data that is into the thousands, you might want to consider implementing a pagination of some sort. If it's just a couple hundred, then I don't think you need to worry too much about the performance of a.removeAll();

Flex: select tree node right after the dataProvider is been assigned / updated / replace

i have a Flex tree control and im trying to select a tree node 3 levels down right after the dataProvider is assigned with a collection object like the following.
basically treeItem1, treeItem2, treeItem3 are the nodes in the tree and treeitem3 is a child of treeItem2 which is a child of treeItem1. Assume these treeItem(1,2,3) are referenced correctly from the collection items.
my problem is that if i wait for the whole component to load completely then select the nodes, it open/select/scrolltoIndex correctly. However, if i were to select the node right after the dataProvider is assigned, then it doesn't even open or select (basically the this.treeService.selectedItem is always null).
can anyone point out what i did wrong? is there anything needs to happen after the dataProvider is assigned?
thanks
this.treeService.dataProvider = oPricingHelper.getCurrentPricingSercicesTreeSource();
this.treeService.expandItem(treeItem1, true);
this.treeService.expandItem(treeItem2, true);
this.treeService.selectedItem = treeItem3;
this.treeService.scrollToIndex(this.treeService.selectedIndex);
I have used the updateComplete event to know when a component (such as a DataGroup or List) has completed rendering after performing a simple task (such as updating the dataProvider reference). Of course, you have to be careful and remove listening to updateComplete because it can run a lot, unless you have a need for it to run.
Something like:
//...some function...
this.treeService.addEventListener(FlexEvent.UPDATE_COMPLETE, onTreeUpdateComplete);
this.treeService.dataProvider = oPricingHelper.getCurrentPricingSercicesTreeSource();
//...rest of some function...
private function onTreeUpdateComplete(event:FlexEvent):void {
this.treeService.removeEventListener(FlexEvent.UPDATE_COMPLETE, onTreeUpdateComplete);
this.treeService.expandItem(treeItem1, true);
this.treeService.expandItem(treeItem2, true);
this.treeService.selectedItem = treeItem3;
this.treeService.scrollToIndex(this.treeService.selectedIndex);
}
I'm not positive your experiencing the same issue but I seem to have the same type of problem with using the advanced data grid, it appears in these cases where the dataprovider is acceptable as multiple types, the components do some extra work in the background to wrap things up into something Hierarchical (HierarchicalData or HierarchicalCollectionView) and in doing so the dataprovider setter call is not synchronous (so it will return before actually having assigned the internal property storing the dataprovider). I've used callLater in this case with moderate success, callLater is generally a bad practice but basically adds a function to a list of functions to call once background processing is done, so this is assuming that something in the dataprovider setter called UIComponent.suspendBackgroundProcessing() and that it will subsequently call UIComponent.resumeBackgroundProcessing() and then it will execute the list of functions added by using callLater. Alternatively you could use setTimeout(someFunction,1000).
These are both "hacks" the real solution is to dig into the framework code and see what it's really doing when you tell it to set the dataprovider. Wherever you see that it actually has set the dataprovider you could extend that class and dispatch an event that you could listen for to run the function to do the selections after this point.
If anyone has a better solution please by all means correct me (I would love to have a better answer than this)

Weird problem with a custom bindable class and a vector

I'm having a very weird problem with a vector in my application.
Details...
I have the following classes.
Person,Player,PlayerController.
Player extends Person. Person extends ObjectProxy in order to enable binding.
So the Player class has the [Bindable] tag.
The PlayerController class contains a remote object calling a php method to receive a firstname and a lastname and when the CallResponder gets the result from the call,the result handler creates a Player instance. At that moment I am trying to push the player object into a Vector..
The problem is the following.
Every time the push method is called, the vector is being populated with the last player that was created but not just in the end of the vector. It replaces the other instances as well! So the vector always contains the most recent player instance but in every position of it. :S
I have also tried doing it with an Array and the results are the same.
Any thoughts on what I'm doing wrong? It's driving me crazy. :S
My guess is that you are pushing the same object reference into your vector after setting that reference to a new instance of Player, meaning that all of the items in your vector refer to the same object, which is always the newest object. I say "guess" because I haven't seen your code. What are you pushing into your vector, a local variable? A member variable?
Edit: Based on your comment below, try adding your new Player object to your vector using a local variable rather than from your member variable (player_):
var newPlayer:Player = new Player();
newPlayer.firstName = results[firstName];
newPlayer.lastName = results[lastName];
players_.push(newPlayer);
player_ = newPlayer;
You are doing what I suspected, which is adding multiple references to the same object to your vector. Since all of the references in your object refer to the same object, changing the one object changes ALL of the entries in your vector. Doing the above will create a brand new (and unique) Player object each time you add to your vector.

clone flex component

I am trying to duplicate a flex component at run time.
For example if i have this
mx:Button label="btn" id="btn" click="handleClick(event)"/>
i should be able to call a function called DuplicateComponent() and it should return me a UI component thts exactly same as above button including the event listeners with it.
Can some one help me please??
Thanks in advance
Do a Byte Array Copy. This code segment should do it for you:
// ActionScript file
import flash.utils.ByteArray;
private function clone(source:Object):*
{
var myBA:ByteArray = new ByteArray();
myBA.writeObject(source);
myBA.position = 0;
return(myBA.readObject());
}
One note, I did not write this code myself, I'm pretty sure I got it from a post on the Flex Coder's list.
To solve that problem you should use actionscript and create the buttons dynamically.
Lets say you want the button(s) to go in a VBox called 'someVbox'
for (var i:uint = 0; i< 10; i++){
var but:Button = new Button();
but.label = 'some_id_'+i;
but.id = 'some_id_'+i;
but.addEventListener(MouseEvent.CLICK, 'handleClick');
someVbox.addChild(but);
}
I haven't tested it, but that should add 10 buttons to a vbox with a bit of luck.
You can't take a deep copy of UIComponents natively. You're best bet would be to create a new one and analyse the one you have to add a duplicate setup. To be honest this does sound like a bit of a code smell. I wonder if there may be a better solution to the problem with a bit of a rethink..
Same question as: http://www.flexforum.org/viewtopic.php?f=4&t=1421
Showing up in a google search for the same thing. So you've cut&pasted the same question a month later. No luck eh?
There is no easy way to do this that I know of. Many of a component's settings are dependent on the container/context/etc... and get instantiated during the creation process, so there's no reason to clone from that perspective.
You can clone key settings in actionscript and use those when creating new elements.
For instance, assuming you only care about properties, you might have an array ["styleName","width","height",...], and you can maybe use the array like this:
var newUI:UIComponent = new UIComponent();
for each(var s:String in propArray) {
newUI[s] = clonedUI[s];
}
If you want more bites on your question (rather than waiting a month), tell us what you are trying to achieve.
mx.utils.ObjectUtil often comes in handy, however for complex object types, it's typically good practice to implement an interface that requires a .clone() method, similar to how Events are cloned.
For example:
class MyClass implements ICanvasObject
{
...
public function clone():ICanvasObject
{
var obj:MyClass = new MyClass(parameters...);
return obj;
}
}
This gives your code more clarity and properly encapsulates concerns in the context of how the object is being used / cloned.
You are right but as per my understanding UI Components are not cloned by mx.utils.ObjectUtil.
from : http://livedocs.adobe.com/flex/201/langref/mx/utils/ObjectUtil.html#copy()
copy () method
public static function copy(value:Object):Object
Copies the specified Object and returns a reference to the copy. The copy is made using a native serialization technique. This means that custom serialization will be respected during the copy.
This method is designed for copying data objects, such as elements of a collection. It is not intended for copying a UIComponent object, such as a TextInput control. If you want to create copies of specific UIComponent objects, you can create a subclass of the component and implement a clone() method, or other method to perform the copy.
Parameters value:Object — Object that should be copied.
Returns Object — Copy of the specified Object

AS3 Memory Conservation (Loaders/BitmapDatas/Bitmaps/Sprites)

I'm working on reducing the memory requirements of my AS3 app. I understand that once there are no remaining references to an object, it is flagged as being a candidate for garbage collection.
Is it even worth it to try to remove references to Loaders that are no longer actively in use? My first thought is that it is not worth it.
Here's why:
My Sprites need perpetual references to the Bitmaps they display (since the Sprites are always visible in my app). So, the Bitmaps cannot be garbage collected. The Bitmaps rely upon BitmapData objects for their data, so we can't get rid of them. (Up until this point it's all pretty straightforward).
Here's where I'm unsure of what's going on:
Does a BitmapData have a reference to the data loaded by the Loader? In other words, is BitmapData essentially just a wrapper that has a reference to loader.content, or is the data copied from loader.content to BitmapData?
If a reference is maintained, then I don't get anything by garbage collecting my loaders...
Thoughts?
Using AMF a bit with third party products has lead me to believe the Loader class attempts to instantiate a new class of the given content type (in this case it would be a Bitmap class instance). You are probably constructing a new BitmapData object from your Bitmap instance. From that I would assume that the Loader instance references the Bitmap instance, and in your case your code also references the Bitmap instance. Unless at some point you are calling BitmapData.clone().
There are also a couple of ways to force GC. Force Garbage Collection in AS3?
You may find it useful to attach some arbitrarily large object to something, then force the GC to see if that thing is getting cleaned up or floating around. If you are using Windows something like procmon (http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx) is more helpful than task manager for doing this kind of external inspection.
This of course is a bit trial and error but for lack of something like Visual VM (https://visualvm.dev.java.net/) we are kind of screwed in the Flash world.
It's a good question, but to the best of my knowledge, the answer is no -- neither Bitmap nor BitmapData objects possess references to the loaders that load them, so you can safely use them without concern for their preventing your Loaders from being collected.
If you want to make absolutely sure, though, use the clone() method of the BitmapData class:
clone()
Returns a new BitmapData object that
is a clone of the original instance
with an exact copy of the contained
bitmap.
For example:
private function onCreationComplete():void
{
var urlRequest:URLRequest = new URLRequest("MyPhoto.jpg");
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loader_complete, false, 0, true);
loader.load(urlRequest);
}
private function loader_complete(event:Event):void
{
var img1:Image = new Image();
img1.source = Bitmap(event.target.content);
addChild(img1);
var img2:Image = new Image();
img2.source = new Bitmap(event.target.content.bitmapData.clone());
addChild(img2);
}
Here, img1's source is a Bitmap cast explicitly from the BitmapData object returned by the loader. (If you examine the references in FlexBuilder, you'll see they are identical.) But img2's source is a clone -- new bunch of bytes, new object, new reference.
Hope that helps explain things. The more likely culprits responsible for keeping objects from being garbage collected, though, are usually event handlers. That's why I set the useWeakReference flag (see above) when setting up my listeners, pretty much exclusively, unless I have good reason not to:
useWeakReference:Boolean (default =
false) — Determines whether the
reference to the listener is strong or
weak. A strong reference (the default)
prevents your listener from being
garbage-collected. A weak reference
does not.
you may set a variable in the complete listener that stores the bitmap and then destroy the object later
public function COMPLETEListener(e:Event){
myBitmap = e.target.loader.content;
}
public function destroy(){
if(myBitmap is Bitmap){
myBitmap.bitmapData.dispose();
}
}
works fine for me load some big image and see the difference in the taskmanager

Resources