Main

March 11, 2008

Custom ArrayCollections, Adding New Items to DataGrid

The previous posts used custom ILists to merge or concatenate other ILists. This example uses a custom subclass of ArrayCollection to fake an empty object at the end of the actual ArrayCollection which can be used to add new entries to the DataGrid.

If the user fills out the new entry, it is added to the actual collection and another new entry is faked. Additional logic dictates that if the user strips all information out of an entry, that entry is removed from the actual collection.

Usual caveats apply

Download Source
Run Demo

March 10, 2008

Custom ILists, ComboBox Prompts

Following up on the last post which showed how to use custom ILists to merge two collections, this post shows how to use a custom IList to concatenate or append two collections.

Such a thing might be useful in a situation where you want to add more than one prompt to a ComboBox. In the example, I have the days of the week to choose from, but also want to add "Every Day", "Weekdays" and "Weekends" without modifying the original days of the week collection. Of course, if you concatenate the two collections, it offsets your selectedIndex.

Download Source
Run Demo


March 08, 2008

Custom ILists, CheckBoxDataGrid, Merged Arrays

Earlier I published how to do a CheckBoxDataGrid where the selection model uses CheckBoxes instead of mouse clicks. I should have mentioned that the example used the DataGrid's selection logic which meant that the dataprovider item's selected state was not stored in the dataProvider and thus you couldn't sort by whether an item was selected or not.

If you have a selected field in your data, then the code to handle checkbox selection is quite different. You basically shut down the DataGrid's selection code and update the collection instead. You can see that in the source code for this example.

This example goes one step further, however. It assumes that you want to store selection in the dataProvider, but the dataProvider items don't have a selected field and are "immutable". The example code shows how to use a custom IList to merge two arrays or ArrayCollections into one merged collection where the data objects contain fields from both arrays. By doing that you can "add" a selected field to each item.

Custom ILists are a powerful way to change data without having to process each data item. The example code merges the items on-demand instead of up-front thus saving startup time. It would be wasteful to process 1000 items if you only show 7 and the user doesn't scroll past 20.

Anyway, here's the code. Usual caveats apply.

Download Source
Run Demo

March 07, 2008

DataGrid Double-Click To Edit

Several people have asked about changing the default editing behavior of a DataGrid so that starting an edit session requires a double-click instead of the default single-click.

Here's my approach:

Download Source
Run Demo

March 02, 2008

Smooth Scrolling List

One of the features that got cut from 3.0 was "smooth scrolling". List and other list-related classes scroll by row/column which can be a bit choppy at times. We tried to leave the hooks in to allow someone to do it, but we ran out of time to finish the job.

It's too bad we didn't finish the job as there are some difficult things to workaround in trying to get smooth scrolling to work, but I cooked this prototype up to give you a sense for how you might be able to get it working in your apps. Note that the prototype assumes that all rows are the same height. If you have variableRowHeight, that's a whole different problem.

Usual caveats apply, and no, I don't currently have time to make examples for TileList and DataGrid. Maybe some one else will have the time.

Download Source
Run Demo

January 02, 2008

SelectedItem and ComboBox

Seems like it is once a month where someone is having trouble setting the selectedItem of a ComboBox. The key is that the ComboBox does an exact reference match on the items in the dataProvider. It doesnt take the time to compare values within the dataProvider items with the values in the item you are setting as the selectedItem.

In other words, if you have an array of objects:

[{ firstName: "Alex", lastName: "Harris" }, { firstname: "Alex", lastName: "Harui"}, {firstName: "Alex", lastName: "Trebek"}]
you can't just set:
selectedItem = { firstName: "Alex", lastName: "Harui }
as that assigns the selectedItem to a different Object instance with the same values. The ComboBox class will simply look to see if there is a reference to that instance in its dataProvider, which there is not. Instead, you have to scan the dataprovider and match up values.

So many folks are doing this, that I decided to post an example so we don't have to keep writing that scan-the-dataprovider loop. This example tries for an exact match first, so if you know you'll never have an exact match you can save more time by cutting out that first call to super.selectedItem = value;

Source for ComboBox subclass

Test file source
Helper class source for Test file

Test file

Usual caveats apply.

January 01, 2008

Threads in Actionscript 3

Every once in a while, someone decides they would like to see threading or background processing in Actionscript. While the underlying Flash Player and Operating System use threads, the execution model for Actionscript does not.

For those who don't know, 'threading' is essentially the ability to have the code do something in the background while the UI is doing something else. Because Actionscript is single-threaded, if you spend lots of time doing heavy computation, the UI cannot be updated while you're doing that computation so your application appears stuck or effects don't run smoothly.

Similarly, there is no yielding or blocking in Actionscript either. If the next line of code is supposed to run, you cannot prevent the next line of code from running. That means that when you call Alert.show(), the next line of code following that runs right away. In many other runtimes, the Alert window has to be closed before the next line of code continues.

Threading may be a feature of Actionscript some day, but until then, you have to live with the fact that there is no such thing right now.

In other single-threaded environments, you can get something like threads via 'pseudo-threading', which involves dividing up the heavy computation into small chunks on your own. (There is no solution to allow for blocking or yielding other than refactoring the application to be even-driven). Pseudo-threading is painful, but doable in most situations. Iterative tasks are easier than recursive ones, the chunk size has to be small enough to not degrade the UI response time and restoration of the execution context must be efficient otherwise you'll spend too much time saving and restoring your state and not get anything done.

Someone asked me how I would generalize such a thing. I put this together in a couple of hours. It represents my first thoughts, not some deep thinking on the subject. A PseudoThread instance takes a callback function and a context object and calls the callback function with the context object as mahy times as it thinks it can get away with it within the frame interval. The callback function should update the context object before returning and return false when done and the PseudoThread instance dispatches an event and destroys itself.

PseudoThread.as

The following is the a test that loads an image, and adds a red tint to a copy of the image one row at a time. I purposefully slowed it down with trace statements so you can see that it doesn't do it all at once and doesn't seem to affect the rotating button.

PseudoThreadTest.swf

These two links are the source file and the test image.
PseudoThreadTest.mxml
the test image

The usual caveats apply (there are probably bugs, limitations, etc). Hope it helps.

HTML and Flex

In case you didn't know, the Flash Player is not very good at displaying HTML content. Since the Flash Player is the foundation for Flex, Flex apps deployed on the Web aren't very good at displaying HTML either. In the Adobe AIR Player, essentially a full browser is built in and HTML content is rendered faithfully. However, the amount of code required to display HTML in AIR is measured in megabytes and is too large to be included in the Flash Player download at this time.

Various folks have made reasonable attempts to get something to work in Flash. There is the DENG project . And popular among many Flex developers is the third-party HTMLComponent which uses the IFrame trick to display HTML "over" chosen areas in your Flex application. FABridge lets you integrate your Ajax application with Flex widgets.

None of these solutions are fully-integrated with Flex in the sense that the HTML is part of the Flex DOM. Right after 2.0 shipped, I was doing some testing on how fast Flash Player 9 and ActionScript 3 was and hacked together a little test which grabs an XHTML file, parses it using E4X, and creates a UIComponent for every HTML tag and one or more TextFields for every run of text. It ran suprisingly fast. I put it down to get on to Flex 3 work and poked at it a bit since then. I finally found time to fix post this code. You'll see that there are many bugs and missing features.

To fully finish off HTML rendering and CSS, fix bugs, etc in this code is outside of the scope of Adobe's focus at this time. It might make a great community project if some of you want to take on the effort. I'm no expert in HTML so you may or may not want to start with the code attached here. This test just proves the feasiblity of mapping HTML tags to UIComponents so there is better integration with Flex and better HTML rendering than you can currently get in the Flash Player.

Source Code for flex.html.*
Source Code for test files for flex.html.*
SWFs, HTML, etc for test files for flex.html.*

The zips can be imported into FlexBuilder 3. I didn't post the SWFs because you need to run out of your local sandbox to get around security restrictions, so it is best to download the files, import the projects, build them and run them.

Personally, I don't believe most of you need a full browser. You probably just have 'plain' HTML documents that don't run scripts, don't do fancy DIV stuff like wrapping text around images, etc. So you might be able to fix a few bugs and get what you want to work in relatively short order. You probably also don't need to wade through hand-authored HTML and 'bad' HTML. All of that sutff adds weight to the code.

For example, htmltest3 in the test zip is test for the superscript/subscript tags. Maybe all you need is a few tags like those plus bold and italic.

The hmltest2 test also shows the principle of dynamic UI. You can send your UI over as XHTML and by wrapping your Flex component appropriately, you can generate the UI from the XHTML description. Notice the DataGrid in the document.

The code has an IHTMLElement interface so you can talk to it in DHTML/AJAX-like ways. There's even the beginnings of an XMLHTTPRequest class. There is also a class that tries to clean up bad HTML.

Have fun, hope it helps, and DO NOT REPORT BUGS. I will probably delete all comments reporting bugs as this is totally unsupported by me.




October 03, 2007

ActionScript Read/Write Performance

Reading, Writing and Arithmetic

ActionScript 3 (AS3) on FlashPlayer 9 has delivered on its promise of much improved performance. Sure, we’ll probably always wish it could be faster, but it is much better than ActionScript 2 (AS2). In AS2, everything was essentially dynamic. You could add properties to classes at runtime, change their types, modify methods, and all kinds of evil tricks. This required a certain amount of overhead at runtime to allow for this because you couldn’t know up front what a property was and how to access it.

AS3 introduced ‘sealed’ classes (classes that are not dynamic). Sealed classes cannot have properties added to them or those other nasty AS2 tricks. As such, the runtime can make assumptions about how to access that property. AS3 also implemented Ecmascript For XML (E4X) which made it possible to access the pieces of an XML hierarchy as if they were all objects, using the ‘.’ syntax. This is a vast improvement over the old way of working with XML in AS2.

One of the prices paid for this faster access is the notion of change detection. If objects do not have change detection by default, you can write to them faster as well. However, if you want to detect changes you have to add code to do so. AS3 provides a Proxy class that builds in change detection, and Flex provides [Bindable] metadata that the compiler detects and generates different code to handle change detection.

This means that there are a variety of objects (sealed, dynamic, proxy, bindable, XML, etc) that you can read from and write to in your application. These different objects have different read and write times. The basic runtime of AS3 is very fast so most if the time you won’t care about this information and will use the type of object most convenient to you, but in case you’re wondering, I put together a little test to see how fast things really are.

The test methodology is pretty rudimentary. Call getTimer(), save away the value, run a sequence of code, call getTimer() again and see what the difference is. Various things can cause errors in such testing, but a couple of runs showed reasonable consistency since I was most interested in relative time instead of absolute time. As such, your mileage will vary based on your environment, but here’s what I learned:

Reading

As promised, reading a variable from a sealed class is very fast. My tests accessed variables 200,000 times in just 2ms or less! Everything else was notably less fast, but remember, most of the time, this won’t matter to you, or the cost of optimization may be prohibitive, but here are the numbers anyway. The results will be reported in the following format: a title, a number, and my thoughts on the results. For this first batch of tests, the basic loop looks lke:

for (i = 0; i < counter; i++) {
s = obj.label;
s = obj2.label;
}

where obj and obj2 are local variables typed as sealed classes, Objects, XML or a Proxy subclass, so the compiler knows exactly how to access the data

Reading From Dynamic Object: 40

This means that reading from a dynamic object (created using { label: “foo” }) took roughly 40ms compared to the sealed class variable’s time of around 2ms. This implies that reading from a dynamic object is 20 times slower than reading from a sealed class. So, if you know the set of properties and access them often, define a class instead of using Object. You’ll also get compilation errors if you mis-type a property name.

The reason I’m just using numbers and not times in this report is because the actual amount of time will vary based on your computer’s speed, so numbers give you a relative feel. You’ll see that nothing else runs its test in 2ms, and that there are numbers in the 40-100 range which means that the difference is probably ignorable since it would take 2,000,000 reads to cost your application 400ms such that someone might notice a half-second. Scenarios with numbers in the 300-800 range might we worth your consideration for optimization, but remember, it still took 200,000 reads or writes to add up to less than a second of time.

Anyway, here’s the rest of the results.

Reading From Proxy: 350

That’s right, reading from a Proxy object is significantly slower!. But if you need change detection, you have to pay a price. While that number seems scary, note that it took 200,000 accesses to cost and additional 350ms, so like I said, many times you won’t notice.

Reading From Sealed Classes via Getters: 38

Many times, you’ll actually implement properties as getter/setter pairs instead of plain ‘vars’ because they can be overridden, more logic can be added to the getters or setters (especially to do change detection), or because the properties are defined in an interface. In fact, the vast majority of properties you access in a Flex app are getter/setters so you’re almost always paying this overhead. It is essentially just as fast as dynamic objects, but is much faster than Proxy if you also need change detection. Note also that these numbers are for the simplest getter that just returns a backing variable.

Reading XML Attributes: 550

Yes, that’s right, E4x is slow. But it sure is convenient, and if you had to use other functions to get at the attribute, it would be even worse. However, if you access the same attributes many times, it might pay to convert them to sealed classes or dynamic objects first. And this is simple obj.@label access, not some deeper fetch.

Reading XML Sub-Node: 750

Reading sub-nodes is even slower than reading attributes, so if you have a choice, attributes will be faster, but still not like converting to sealed classes or objects.

More Results

The first set of tests assumed you knew the type of the object you are reading. Often, we don’t know, or don’t know right away. For example, in an event handler, the event.target is typed as Object but you often know it is some other type, and arrays are not typed so when you are indexing into an array to get an object, you have to think about whether to coerce to a known type or not. So, the next set of tests I ran examined reading and writing when pulling objects from an array. The basic loop looked like:

for (i = 0; i < counter; i++) {
obj = arrObject[0];
s = obj.label;
obj = arrObject[1];
s = obj.label;
}

where the arrObject array might contain sealed classes, XML, etc, and obj is or isn’t strongly typed.

Reading From Sealed Class Variables (Coercion): 24

The benchmark for these test is reading when we have a local variable of the correct type and coerce the array entry via:

var lv:SomeClass = SomeClass(arrClass[1]);

That more or less says the price of coercing 200,000 times was some 24ms on my computer, so it is very inexpensive and will give you type-checking at compile time.

Reading From Sealed Class Variables (as): 30

This implies that coercion using “as” is slighly slower than coercion via a function as in the previous test.

Reading From Sealed Class Variables as Objects: 90

This says that it actually pays to coerce objects to known types before accessing variables, otherwise your reads can be 3 times slower.

Reading From Sealed Class Getters: 60

This says that coercion overhead starts to drown out the difference between access via vars vs getters, but there is still a cost. However, most of the time you don’t really have a choice whether to use vars vs getters.

Reading From Bindable Class: 60

This says that if you make a class [Bindable] you are converting the vars to getters and paying the required price for doing so.

Reading Objects: 45

This says that it is worth the cost of defining sealed classes and doing the coercion in the loop, unless the sealed class is using getters in which case it is slightly faster. I’d still go with sealed classes for the type-checking benefits.

Reading Proxys: 370

Proxys are slow. You should use [Bindable] on sealed classes instead. Note also that ArrayCollection is a Proxy so [] access is way slower than [] access of the internal array. It’s probably even faster to use getItemAt() than [] access.

Reading XML Attributes: 575
Reading XML Sub-Nodes: 770

XML is even slower than Proxys. As mentioned earlier, you’d have to access the same attributes quite often in order for it to be worth the cost of converting the XML to objects, but there’ll be occasions where it is worth it.

Writing

A similar loop was used to test writing to properties. We take objects from an array, coerce to a local variables if necessary, then write to a property. The results are:

Writing To Sealed Class Variables: 450

Reading may be fast, but writing is still slow, almost 20x slower than reading (450 / 24).

Writing To Sealed Class Setters: 930

Writing to the most simple setter that dispatches a change event is twice as slow as writing to variables.

Writing to Bindable Sealed Class: 1030

Bindable is slightly slower because it takes the time to do a value changed check before dispatching an event.

Writing to Dynamic Object: 500

Sealed classes are slightly faster unless they use setters, but that’s the price you pay for change detection and compile-time checking

Writing to Proxy: 830

Proxy is only better in this case because it didn’t send a change event. If it did it would probably be slower than sealed classes with setters.

Writing to XML Attributes: 580
Writing to XML Sub-Nodes: 950

No surprise here. XML isn’t very fast, but is very convenient.

Writing to XML Attributes That Have Binding: 7700
Writing to XML Sub-Nodes That Have Binding: 8900

This is the big surprise. XML data binding is very expensive in terms of the cost of modifying the XML data.

Arithmetic

The main takeaway is that XML is slower than objects, but its convenience might outwiegh the performance considerations. Note, though, that anytime you shove XML into an XMLListCollection all of the nodes get setup for binding so the cost of modifying those nodes might be measurable if you do a lot of modifications, and conversion to object may reap benefits.

There’s no easy way to test the speed of converting an XML tree to objects. Our WebService code has functionality that does the conversion, but the speed will depend a lot on the kinds of XML data you are getting. However, it has occurred to me that the conversion code converts the entire tree, and maybe a custom collection could convert on the fly and save the big hit of converting lots of nodes if the query returns a large chunk of XML when only a few nodes might be seen in a list. Hopefully I’ll get to that someday soon and blog about it.

Other than that, unless you really care about saving a tenth of a second here or there, you probably don’t have to think about which data types you are using, but if you want to impress your friends at holiday parties, you can memorize these numbers and recite them. To decide whether to optimize is pure arithmetic. Look at what it would take to convert to a faster access method vs how many accesses you are doing and what the expected payoff might be and decide from there.

Credits

Thanks to Scott from Fast Lane and Tracy Spratt for getting me started on this topic

Additional Information about XMLListCollection

In Flex 2.x, XMLListCollections eat lots of memory. That’s how I originally got started on this topic as Tracy pointed me to Scott’s blog. I’m unconvinced that it is really a leak, but the memory utilization is such that it doesn’t matter. This kind of memory utilization can cause paging in the operating system and exacerbate the performance cost of using XML. Changes were made in Flex 3 Beta 2 to address this problem and memory utilization is better and bounded, but still not as good as objects, so some of you may also want to convert from XML to objects for this reason as well.

June 24, 2007

Disabling List Selection

Recently a couple of FlexCoders asked about how to prevent certain entries from being selected in a List or Tree or ComboBox. I cobbled this together. Usual caveats apply. Hopefully it will help.

Run Demo
Download Source

April 19, 2007

Icons in ComboBox

Somebody recently asked on FlexCoders about how to get icons to show up in the ComboBox. Here's how I'd do it.

Download Source

Run Demo

April 09, 2007

Multiline Buttons

Someone recently asked about having the label of a radiobutton wrap onto more than one line. Maybe it just got lost in FlexCoders traffic because I'm sure others have already solved this, but I put together this version out of my own curiosity. The pattern can be re-used for Button and CheckBox as well. The usual caveats apply.

Download file

You'll notice that I used "undocumented" methods to accomplish this, so it might break in some future release of Flex. However, this is really intended to be another example of subclassing and illustrate that by knowing the underlying base class you can usually tweak things the way you want them.

Now you may ask, why doesn't this functionality come built-in with Flex? The answer is that text-flow is slow and doesn't really work well with the Flex layout system. That's because there really is no way to determine the size of a block of text unless it is only one line or has line-breaks in it or you know its width. In fact, to use this example, you need to specify the width of the radiobuttons, so it defines a width so we can calculate the height.

March 07, 2007

Welcome

Welcome. I finally got motivated to join the rest of the world and start a blog. This one is all about Flex-related things. I've been developing components for Flash and Flex for almost five years. My main areas of expertise are the UI-related code, most of the manager classes, and things related to loading swfs.

My goal is to put things on here related to things that I hear asked often, and maybe some half-baked things as well. We'll see how often I can get over here.