SWFLoader loading multiple apps and using the same Singletons generates a RTE

August 31, 2007

Today I was working with a baffling bug in the Flex Bug Base. It was titled “SWFLoader loading the same app twice, which contains Button which pops up alert will throw RTE when clicked on the second button” and you can see it here SDK-11910

I did a whole lot of debugging and finally needed help from Nisheet… to get to the bottom of the issue. The issue is as follows…

You have multiple apps loaded into a main app using a SWFLoader. Now each of the apps loaded use one of the singletons used in the framework (in the case of the bug, it was the PopUpManager, as the person was using an Alert in the sub App). When he tries to use the methods of the Singleton (in this case thru the Alert.show() method in each of the sub apps), it works for only the first sub app and all others generate the following RTE (Run Time Error) for the others

TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mx.managers::PopUpManager$/addPopUp()
at mx.controls::Alert$/show()

In his case, each of the sub app had the following code (Sample.mxml)…

<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml&#8221; layout=”absolute”>
<mx:Button label=”Click me” click=”mx.controls.Alert.show(‘Button selected!’);”/>
</mx:Application>

And his main app was as follows (main.mxml)…

<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml”&gt;
<mx:SWFLoader id=”swfloader” source=”Sample.swf”/>
<mx:SWFLoader id=”swfloader2″ source=”Sample.swf”/>
</mx:Application>

The following execution map resulted in the RTE

  1. The main app starts and loads the sub apps
  2. When the user clicks the button in the first sub app, the SWFLoader asks its parent if it has an instance of the IPopUpManager interface.
  3. Since the main app has not created or cached its IPopUpManager, it replies negative and the sub app goes ahead and creates one for itself and pop’s the Alert
  4. Now when the user clicks the button in the second subapp, it again repeats Step 2 & Step3
  5. But in Step3, it encounters a code in the framework (in PopUpManager.as)
      private static var impl:IPopUpManager = Singleton
      .getInstance(“mx.managers::IPopUpManager”) as IPopUpManager;
  6. This casting using the as operator fails and thus generates the RTE.

The solution for this is to initialize the main app such that it creates and caches its own IPopUpManager interface, so that both sub-Apps can use the same, without any conflict. The altered main.mxml would look like this

<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml&#8221; initialize=”initApp()”>
<mx:Script>
<![CDATA[
import mx.managers.IPopUpManager;

private function initApp():void{
IPopUpManager;
}
]]>
</mx:Script>
<mx:SWFLoader id=”swfloader” source=”Sample.swf”/>
<mx:SWFLoader id=”swfloader2″ source=”Sample.swf”/>
</mx:Application>

This solves the issue. Please Note that this same step has to be taken, also when your sub apps share other managers like CursorManager, HistoryManager…etc.


Binding in MXML & AS

August 30, 2007

Binding is one of the very useful feature in Flex. Though most intermediate programmers know how to bind a variable in mxml… most are clueless how to achieve this in AS. I’ll discuss both these aspects here.

Binding in MXML

Lets look at the following code…

<mx:TextInput id=”ti1″/>
<mx:Label id=”label1″ text=”{ti1.text}”/>

Here you are binding the text property of the TextInput to the label. So whatever you type in the textInput automatically reflects in the label. That’s the power of Binding…

Binding in AS

This is not as simple as binding in mxml. But it is simple enough…

The key to this is a class called BindingUtils in the mx.binding.utils package. You can use this class as below…

You have your components say in mxml as follows

<mx:TextInput id=”ti1″/>
<mx:Label id=”label2″/>

Now you impost the Binding utils class in the script tag

import mx.binding.utils.BindingUtils;

Then you use the bindProperty method to do the binding in AS as follows…

BindingUtils.bindProperty(label2,”text”,ti1,”text”);

This binds the ti1.text to label2.text. And you are set with your binding…

Binding is specially useful in data related components like List, DataGrid, Charts…etc. You can bind the dataProviders of these components to ArrayCollections or results of HTTPService objects, so that any change in data, immediately reflects in on the component


Assigning different behaviors on click & doubleClick

August 10, 2007

This interesting issue was posted by Arpan on the flex_india group (Read it here). He says…

In my application i have a datagrid with itemrenderer as charts and I need have to perform two operations – one on single click and one on double click – on the chart. But most of the times double click event is not fired and if fired then single click is also fired. Can I stop single click event if double click event is fired ?

I investigated this and found this to be true. Once you enable doubleClick (by setting the doubleClickEnabled flag), whenever it occurs, a click event is also fired with it… I discussed this with Sreeni and he said that this is because the framework intends not to skip any event (because a double click is actually a click followed by a doubleClick event).

This may be useful in a lot of cases, but in Arpan’s case, this was causing havoc. The way to work around this is to write a Timer/Interval and use it to work around the problem. The following is the execution path…

  • On click, in the click handler, reset and initiate the timer which on complete, calls the deferredClickHandler (where the actual clickHandler code sits
  • If doubleClick does not occur, the timer completes and then executes the deferredClickHandler (I have kept my timer to be 300 mS)
  • If doubleClick occurs, it goes to the doubleClick handler, where you clear the timer (so that timer does not complete and execute the deferredClickHandler) and execute the doubleClickHandler code…

Caution: Do not forget to save the initial click Event if you need it later..

In Arpan’s case… he needs to use itemClick and itemDoubleClick events (of type ListEvent) instead of click & doubleClick (of type MouseEvent), as it is a DataGrid. The code below handles the case for both a DG & a Button… I have used the setInterval() method to implement the timer, you may as well use the Timer class…

Application | Source

Thanks to Sameer & Harish who helped me get to the bottom of this…


My Radio Station using Flex & FMS

August 8, 2007

Last week, I created a Radio Station over the Intranet in office. A SWF that I could pass to anyone who could access my machine’s IP Address and lo, they can hear the music that i listen to on my computer at their desk… Cool Eh!

I used Flex as the front-End, with FMS pulling strings at the back-End. I intend to write a tutorial series on this soon. So keep watching this space 🙂


Flex In India – Updates

August 6, 2007

Web2.0 is spreading in India and so is Flex with it 🙂

After a succesful semester of “Web2.0 & RIA (Rich Internet Applications)” elective at IITB, Bangalore (for which, I’m proud to be a part of the visiting industry faculty), the much desired course has now made it into the curriculum of the Visvesvaraya Technological University (VTU).

VTU is a university that has 111 affiliated colleges in the state of Karnataka, in India (kind of apt, as Bangalore, hailed as the Silicon Valley of the East is the capital of this state). The university provides heavily for the demand for IT & Computer engineers for the booming IT & IT Enabled Services industry in the country.

The course ware consists of the following parts…

  • Overview of We2.0 and its perceptions
  • Key concepts in Web2.0
  • Overview of Data Handling in RIAs -This includes technologies like WebServices, E4X, XML
  • Introduction to Open Source Flex2.0
  • Introduction to AJAX
  • … some more

I’m mighty interested and excited about this. Hope I’ll get to be a part of this, just like the IITB venture.

Please, everyone spread the news and ask the students you know to request and signup for this elective in their respective colleges. Lets make this a grand success and a precursor of more to come… Go RIA… Go Flex 🙂


Flex & AS3 Books in India

August 6, 2007

A lot of people complain that there are not enough books on Flex & AS3 in the Indian markets and that they do not know how to get them. This poses a serious threat to the viral adoption of Flex in India. I had a chat on this with John Koch (Adobe Developer Relations Manager, Asia) and he pointed me to some resources.

Shroff Publishers publish a lot of the Oriely books in India and this includes books on Flex2 & AS3 as well.

I haven’t confirmed any, but tomorrow I have decided to phone them and see if these titles are available or not.

Moreover… if you have any more books that you would like to see on Flex, to be published in India, drop me a note. The “Wanna Have List” already includes the following books

  • Rich Internet Applications with Adobe Flex and Java
  • Professional Flex 2 by Rich Tretola, Renaun Erickson & Simon Barber
  • Advanced ActionScript 3 with Design Patterns
  • Essential ActionScript 3

Update 7th Aug 2007:

I called up the retailers asking for the books. They said that if I mail them at their respective email ids, they would get the books for me in a matter of 2-3 days. I did this with the following 2 publishers

1. Gangarams Book Bureau
72, Mahatma Gandhi Road, Bangalore
Phone : 080-25587277 & 25586743
Email : gangarams@vsnl.com

2. Strand Book Stall
S 113 -114, Manipal Centre
Dickenson Road, Bangalore
Phone : 080-25582222
Email : strandbk@bgl.vsnl.net.in

If you dont know where these places are in Bangalore… use Google Maps and search for Gangarams or Strand Book Stall, Bangalore. It will do the trick. Go ahead and order them… Guys in other cities, try this with the book stores in the link given on the above post and let me know, so that I can spread the word 🙂


Jump cuePoints in a Video

August 3, 2007

This was another of those questions that was posted to me by a Flex user in Germany. Thought I’ll share it with all…

The person wants a way, by which you can jump from one cue point to another, in a video. While this is not difficult, I wanted to give a way to tap into all kinds of cue points in this way, namely the ones added thru AS, thru MXL and those which are encoded into the video using the Flash Video Encoder

The application below has a video that has 3 embedded cuepoints (done during encoding time), 2 AS cuepoints and 2 MXML cuepoints. The following are the steps required…

  1. Create a cueArray Object to hold the details of the cuePoints
  2. On creationComplete, access the cuePoints property of VideoDisplay (which is an array), loop thru it and store the ‘time‘ property of the cuePoint into the cueArray object
  3. Then, listen to the metadataReceived event on VideoDisplay and access myVD.metadata.cuePoints to get the embedded cuePoints. Do the same there… (Important: The metadata property on VideoDisplay is only available on Flex3. If you do not have Flex3, skip this step, or better still, go get it)
  4. Once you have the cueArray ready, have an index property that keeps track of the index of the latest cuePoint fired. This is done by tapping into the cuePoint event and then updating the index as…
    index = cueArray.indexOf(event.cuePointTime);
  5. When the user tries to jump to the next cue, set the playHeadTime from the appropriate index and you are done 🙂

CAUTION: What you need to remember here, is the way, the playHeadTime property works…

When you set playHeadTime to say 2.54s, the VideoDisplay tries to set this. But a video can seek only key-frames in a FLV (which is decided by the encoded video data rate on the FLV encoder. This decides the resolution of the FLV). So, even though you set the playHeadTime to 2.54s, it may seek to the closest key-frame in the FLV which may be 2s or 4s (depending on the resolution of encoding)

You can see it here in the app… First let the video play fully, so you can see where all the cue points are. Now, click the “Jump to Next Cue” button and compare the playHeadTime to the cuePoint time. You will not only see that they are different, but also 3 cuePoints at 2.347, 2.45 & 2.6s, all default to 3.5s due to the above design.

Here’s the application and the source (The FLV might take some time to load… its > 2MB in size)

Application | Source

 


Persisting DataGrid column order

August 1, 2007

I found this very interesting question the Flex SDK Forum. The person, wanted to persist the users selection of the re-ordered columns across visits. A very useful addition towards a site for personalization… Here’s the scenario

The user hits your site and gets a DG(DataGrid) with multiple columns. He goes ahead and re-arranges them to his liking and leaves the app. Next time he comes back, he sees the same old screen, with his selections garbled, as the app has now re-started. Is there a way to personalize the DG for him and persist it across SWF re-loads?…

Yes… you can. I had a bit of trouble figuring it out, but got it. I first did what Rob had suggested him to do, which was to push the columns array of the DG to a shared object and to set it back when the app reloads. As he says in his code…

save it as…

var settings:SharedObject = SharedObject.getLocal(“customColumns“);
settings.data.dgColumns = dgXT.columns;

and retrieve it as…

var settings:SharedObject = SharedObject.getLocal(“customColumns“);
if (settings.data.dgColumns != null)
{
dgXT.columns = settings.data.dgColumns;
}

This doesn’t work because, trying to cast the Object to type DataGridColumn, the framework fails and throws a Run Time Error…

Then i tried to get each object from the SharedObject (which involves looping thru the SharedObject as it is of type Array) and then to cast each of the children explicitly, using the ‘as‘ operator as below, but it failed again…

var settings:SharedObject = SharedObject.getLocal(“customColumns“);
if (settings.data.dgColumns != null){
for (var i:int=0; i<settings.data.dgColumns.length; i++){
dgXT.columns[i] = settings.data.dgColumns[i] as DataGridColumn;
}
}

The third attempt was to loop through each of the items in the SharedObject array and then loop thru the object, get the properties and set it to the columns…

for (var i:int=0; i<settings.data.dgColumns.length; i++){
for (var j:* in settings.data.dgColumns[i]){
dgXT.columns[i][j] = settings.data.dgColumns[i][j]
}

}

Still it failed as some of the internal complex types (like IFactory), failed to be cast. I think, the reason is because the SharedObject , considers all the stored objects as purely Objects and does not preserve the type which they belong to.

Then Swaroop gave me an idea… why not save only those values which you require and set them back. I created an object for each of the DG columns which has details on those properties that i need to set back. Then at load-time.. I set them back.

In the method where i save the settings…

var columnArray:Array = new Array();

for(var i:int; i<dgXT.columns.length;i++){
var columnObject:Object = new Object();
columnObject.columnDataField = dgXT.columns[i].dataField as String;
columnObject.columnHeader = dgXT.columns[i].headerText as String;
columnArray.push(columnObject);
}
var settings:SharedObject = SharedObject.getLocal(“customColumns”);
settings.data.dgColumns = columnArray;

And while setting them back…

var settings:SharedObject = SharedObject.getLocal(“customColumns”);
if (settings.data.dgColumns != null)
{
var columnArray:Array = settings.data.dgColumns;
for(var i:int=0;i<columnArray.length;i++){
dgXT.columns[i].dataField = columnArray[i].columnDataField;
dgXT.columns[i].headerText = columnArray[i].columnHeader;
}
dgXT.invalidateList(); //This is to redraw the list
}

And lo… it works 🙂 Feel free to add any more attributes of the column that you would like to save (for starters, may be the columnWidth). You can find the app and the source at the links below (better than the code above as it is documented 😉 )

Application | Source

If you have a better solution… I would like to know 🙂