Showing 1 - 2 of 2 total. RSS Feed WordPress RSS Feed

Copying objects

If you want to create a copy of an object, you can't simply use the assignment operator (=), because it will only perform the copy of the references.


Example
var obj1:Object = {firstName:"John", lastName:"Doe", age:35};
var obj2:Object = obj1;
At the end of an assignment operation you will have two references that point to the same memory location.
Any modification on the first object will be reflected on the other.
The Flex framework contains the ObjectUtil class, which has a copy static method. That method allows you to create deep copies of an object.

Example
var obj1:Object = {firstName:"John", lastName:"Doe", age:35};
var obj3:Object = ObjectUtil.copy(obj1);
Obj1 and obj3 are different references that point to different memory locations. Any modification on obj1 won't be reflected on obj3.
The copy method works well with objects of class Object, but it throws an error when you try to copy, for example, custom classes.

Example
var pers1:Person = new Person();
pers1.firstName = "Lisa"; pers1.lastName = "Redcliff"; pers1.age = 25;
var pers2:Person = ObjectUtil.copy(pers1) as Person;
trace("pers1 last name: " + pers1.lastName + " pers2 last name: " + pers2.lastName);
The trace statement throws an error. This happens because the copy method internally converts the source object in a ByteArray one, duplicates it and then converts the duplicated ByteArray in the destination object.
In other words, a binary AMF serialization/deserialization occurs. If you use custom classes, the Flash Player serializes correctly the source object, but doesn't know how to deserialize according to the specified cast (Person).

For this reason you have to register your custom class in order to give to the player the informations on how to perform the deserialization.
This can be done using the registerClassAlias method, which accepts 2 arguments:

- the fully qualified class name of the object to copy, which can be retrieved using flash.utils.getQualifiedClassName(sourceObj)
- the Class definition of the object, which can be retrieved using flash.utils.getDefinitionByName(className);</div>

After the class registration, the copy method can execute correctly.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="onComplete()">
<mx:Script>
<![CDATA[
import flash.utils.getDefinitionByName;
import flash.net.registerClassAlias;
import flash.utils.getQualifiedClassName;
import com.Person;
import mx.utils.ObjectUtil;

protected function onComplete():void
{
/*-------------------------------------
Case 1: assigning object 1 to object 2
---------------------------------------*/
var obj1:Object = {firstName:"John", lastName:"Doe", age:35};

// The assignment acts on the references: obj1 and obj2 are
// 2 references that point to the same memory location
var obj2:Object = obj1;

// Modifying the age attribute of obj1, we affect also obj2
obj1.age = 45;

// traces "obj1 age: 45 obj2 age: 45"
trace("obj1 age: " + obj1.age + " obj2 age: " + obj2.age);

/*-------------------------------------
Case 2: using the copy method
---------------------------------------*/
// With the copy method the object memory location is copied,
// obj1 and obj3 references point to different memory locations
var obj3:Object = ObjectUtil.copy(obj1);

obj1.firstName = "Ken";

// traces "obj1 first name: Ken obj2 first name: John"
trace("obj1 first name: " + obj1.firstName + " obj3 first name: " + obj3.firstName);

var pers1:Person = new Person();
pers1.firstName = "Lisa";
pers1.lastName = "Redcliff";
pers1.age = 25;

// 1.
//var pers2:Person = ObjectUtil.copy(pers1) as Person;
// 2.
var pers2:Person = copyObject(pers1) as Person;

// Statement 1
// ------------
// throws an error
//
// Statement 2
// ------------
// traces "pers1 last name: Redcliff pers2 last name: Redcliff"
trace("pers1 last name: " + pers1.lastName + " pers2 last name: " + pers2.lastName);
}

/*
The copyObject method calls the copy function only when
the class is registered, so the ByteArray deserialization
can be done correctly.
*/
public function copyObject(sourceObj:Object):Object
{
var className:String = getQualifiedClassName(sourceObj);
registerClassAlias(className, getDefinitionByName(className) as Class);

return ObjectUtil.copy(sourceObj);
}

]]>
</mx:Script>
</mx:Application>

Localizing an application using Resource Modules

If you need to localize an application and you have to support a lot of languages, the classic Resource Bundle approach could be very expensive in terms of swf file size, because it is compiled with all the defined languages.
With Resource Modules, Flex give you the possibility to create separate resource swf files (one for each language), that you can load programmatically, only when needed.
The starting point is the same of the Resource Bundle approach:
  • Create a locale folder inside the project root;

  • Create one folder for each language, named with the locale initials (e.g. en_US, it_IT, fr_FR, etc.);

  • Create a localization file inside each language folder (e.g. localizedContent.properties);

  • Fill each localizedContent file with your localization strings, classes, etc.


Example:

locale/en_US/localizedContent.properties
comboLabel=Select a language
welcome=Welcome to my application
helloLabel=Click to hail
helloMessage=Hello my friend!


locale/it_IT/localizedContent.properties
comboLabel=Seleziona una lingua
welcome=Benvenuto nella mia applicazione
helloLabel=Clicca per salutare
helloMessage=Ciao amico mio!


locale/fr_FR/localizedContent.properties
comboLabel=selectionnez une langue
welcome=bienvenue a ma application
helloLabel=cliqueter pour saluer
helloMessage=bonjour mon ami!

The Resource Modules have to contain not only your defined resources, but also the resources required by the Flex framework.
In order to identify which are the framework resources used by your application, you have to run the following command using the command line:


mxmlc -locale= -resource-bundle-list=resources.txt ResourceModules.mxml


The generated resources.txt file shows the list of framework resources that you have to include in the modules.

The file looks like this: bundles = collections containers controls core effects skins styles

Now you have to create the modules using mxmlc compiler (suppose to have english, italian and french languages):

mxmlc -locale=en_US -source-path=.,locale/{locale} -include-resource-bundles=collections,containers,controls,core,effects,skins,styles,localizedContent -output en_US_resx.swf

mxmlc -locale=it_IT -source-path=.,locale/{locale} -include-resource-bundles=collections,containers,controls,core,effects,skins,styles,localizedContent -output it_IT_resx.swf
mxmlc -locale=fr_FR -source-path=.,locale/{locale} -include-resource-bundles=collections,containers,controls,core,effects,skins,styles,localizedContent -output fr_FR_resx.swf

Three files are generated:

  • en_US_resx.swf;
  • it_IT_resx.swf;
  • fr_FR_resx.swf.

Those are the Resource Modules that we need to localize our application.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
creationComplete="onComplete()">
<mx:Script>
<![CDATA[
import mx.events.ResourceEvent;
import mx.controls.Alert;
import mx.collections.ArrayCollection;

// The current locale: the default is en_US
private var _currentLocale:String = "en_US";

protected function onComplete():void
{
// On creation complete set the locale with a default (en_US)
setupLocale(true);
}

private function setupLocale(forceLoad:Boolean=false):void
{
// Check if the resource is already loaded.
// The forceLoad flag is used to force the loading even if the resource has
// already been imported.
// During the initialization, the en_US loading has to be forced, because the
// english language is automatically included by Flex, but does not contain our
// resource definitions.
if(resourceManager.getLocales().indexOf(_currentLocale) == -1 || forceLoad)
{
// If the resource has not been loaded yet, or forceLoad=true, load the resource module
var dispatcher:IEventDispatcher = resourceManager.loadResourceModule(_currentLocale + "_resx.swf");
// Attach an event listener which has to be called when the module is completely loaded
dispatcher.addEventListener(ResourceEvent.COMPLETE, onResourceLoaded);
}
else
{
// If the resource has already been loaded, simply localize
onResourceLoaded(null);
}
}

/*
The following variables represent the parameters that have to be localized.
*/
[Bindable]
private var _comboLabelText:String;

[Bindable]
private var _welcomeText:String;

[Bindable]
private var _helloLabelText:String;

[Bindable]
private var _helloMessage:String;

private function onResourceLoaded(e:ResourceEvent):void
{
// Set the locale chain
resourceManager.localeChain = [_currentLocale];

// Modify the localization parameters
_comboLabelText = resourceManager.getString("localizedContent","comboLabel");
_welcomeText = resourceManager.getString("localizedContent","welcome");
_helloLabelText = resourceManager.getString("localizedContent","helloLabel");
_helloMessage = resourceManager.getString("localizedContent","helloMessage");


}

[Bindable]
private var _langs:ArrayCollection = new ArrayCollection(
[{name:"English", value:"en_US"},
{name:"Italiano", value:"it_IT"},
{name:"Francaise", value:"fr_FR"}]);

private function onHelloClick():void
{
// The message displayed depends on the selected language
Alert.show(_helloMessage);
}

private function onLangChange():void
{
// When the selected language of the combo box changes,
// the corresponding module is loaded
_currentLocale = langsCombo.selectedItem.value;
setupLocale();
}
]]>
</mx:Script>
<mx:VBox>
<mx:HBox>
<mx:Label text="{_comboLabelText}" />
<mx:ComboBox id="langsCombo" dataProvider="{_langs}" labelField="name" change="onLangChange()" />
</mx:HBox>
<mx:Label text="{_welcomeText}" />
<mx:Button id="helloBtn" label="{_helloLabelText}" click="onHelloClick()" />
</mx:VBox>
</mx:Application>
Showing 1 - 2 of 2 total. RSS Feed WordPress RSS Feed