Custom Binding Released!

Delivered as promised. It has a smaller memory footprint, a faster clock-speed and, best of all, it’s 100% weak-referenced. Data binding is supposed to be light and unobtrusive. Now you can have the smallest ActionScript 3 binding available, released as a component of the open source Flight Framework.

Flight’s data binding is powerful and simple, consisting of two classes. A Binding object represents a single data source: a source object and a source-path, such as model and "user.userName". Any number of event listeners and object/property pairs can be registered with this single Binding instance, allowing each to update when the data source changes. This class may be useful for special needs, but you usually don’t deal with Binding directly.

The Bind class is the primary interface to Flight binding and is used much like you would use Flex BindingUtils. This class exposes a static API for adding and removing bindings and listeners. It can also be instantiated via MXML for special cases where you need weak-reference binding that curly-brace bindings just don’t support. Here’s an example of usage:

Binding via Static ActionScript API:

// Bind.addBinding(target:Object, targetPath:String, source:Object, sourcePath:String, twoWay:Boolean = false):Boolean

Bind.addBinding(this, "userTxt.text", this, "model.user.userName");

Instance binds via MXML:




Visit the Google Project to download release 0.8.1 or higher.

Optimization For Faster Binding

Flight data binding works seamlessly with existing Flex components, responding to the same property update notifications and dispatching similar events. Flight binding is faster at updating and synchronization than Flex’s data binding when using these Flex property change events. But it is even faster if you choose to use Flight’s own property change methods, illustrated below:

import flight.events.PropertyEvent;

[Bindable(event="propertyChange", flight="true")]
public function get userName():String
{
    return _userName;
}
public function set userName(value:String):void
{
    if(_userName != value) {
        var oldValue:Object = _userName;
        _userName = value;
        // any other behavior, updates, etc that should happen with this change
        PropertyEvent.dispatchChange(this, "userName", oldValue, _userName);
    }
}

It takes more code, but by using Flight’s PropertyEvent an event is only dispatched if it is being actively bound to – Flex will dispatch an event for every property change in the system, which creates more performance overhead. In Flight, events are targeted to a specific property change by using a propertyName + "Change" convention – "userNameChange" – preventing an additional listener and response from binds that target other properties.

Flex uses a generic "propertyChange" event that every binding listens to. Bindings in Flex also listen to every single bindable event on the class.Flex will target the events of a single property appropriately. For this reason the unique meta data [Bindable(event="propertyChange" flight="true")] insures that Flight bindings are optimally tuned for performance while still allowing Flex bindings to be usable. To illustrate: if each bindable meta tag where to reflect a unique event (propertyName + "Change"), Flex binding performance would suffer on classes with a significant number of properties because each bind would be listening to every one of these events. Flight presents a custom solution for speeding up binding resolution, yet still has increased performance using regular Flex bindings [Bindable] public var userName:String;

I misinterpreted Flex’s binding procedures and have found that built-in Flex binding will still target a specific property’s bindable events, not the binding events of the entire class. So to get optimal performance from both Flight and Flex binding, the appropriate meta tag should be formatted [Bindable(event="matrixChange")] public var matrix:Matrix;, where the event name is the name of the property + “Change”. Flight’s PropertyEvent.dispatchChange was designed around dispatching this type of event for best performance.


The classes are only just being documented. Like the rest of Flight the binding is seeing an early release and has some polishing left to do. If you try it out I’d love to hear your feedback, positive or otherwise. The Flight Framework group (mailing list) is available here. Enjoy!

30 Comments

  1. Posted on February 17, 2009 at 4:17 pm by Better-than-Flex Binding - Jacob Wright - Flex, AIR, PHP, etc.

    […] and faster than Flex’s but can be used in Flex and even has an MXML tag to create a bind. Check it out. […]

  2. Posted on February 17, 2009 at 5:25 pm by Ben Dalton

    Now if you can patch mxmlc to generate your bindings for the {} shorthand, we’ll be all set :-)

  3. Posted on February 17, 2009 at 6:44 pm by ?Flex????????? | ??'s Blog

  4. Posted on February 24, 2009 at 5:35 pm by Alan

    Any chance for a mailing list?

  5. Posted on February 24, 2009 at 6:05 pm by xtyler

    Way ahead of you Alan! Join Flight Framework | Google Groups

  6. Posted on February 25, 2009 at 4:39 am by localToGlobal » Blog Archive » news review -> 8th week of 2009

    […] > xtyler Custom Binding Released! […]

  7. Posted on March 1, 2009 at 3:08 pm by iongion

    Wonderful, but let me understand, this won’t work when using curly braces ?

    I mean, what wouldn’t work ?

  8. Posted on March 2, 2009 at 11:50 am by xtyler

    Curly brace binding automatically uses the built-in Flex solution, so the benefits of Flight’s binding (such as weak-reference and speed improvements) are lost. In other words, there is no reason to use Flight binding within curly braces. But it wouldn’t hurt anything either.

  9. Posted on March 3, 2009 at 7:05 am by James Ward

    Hi Tyler,

    This is very cool and something that I’ve definitely needed on some projects. Is your Bindable tag a typo? I had to put a comma in to make it compile. Also, I can’t seem to make this work on an ArrayContainer. I’m using the latest Flight from SVN. One last thing… It would be great if I could setup a Logger or something and get some debugging info about the binding stuff. This is one major lacking of Flex’s Binding. It’s a black box so it’s very hard to debug problems.

    Thanks for your hard work on this! Flight is looking great!

    -James

  10. Posted on March 3, 2009 at 9:25 am by xtyler

    I’ll contact you directly about the bugs. As for the logger that’s a great idea – Flight has a logging class that hasn’t really been utilized or stress-tested yet, this might be a good opportunity.

    Thanks James!

  11. Posted on March 6, 2009 at 5:15 am by wolfroma

    PropertyEvent.dispatchChange(this, “userName”, oldValue, _userName);

    This code is such ugly (:
    If you want custom event name you should use metatag [Bindable(“EventName”)], as say before for perfomance you can check listeners.

    [Bindable("sourceChange")]
    public function get source():Object{
        return _source;
    }
    
    public function set source(value:Object):void{
        if(value!=_source){
            _source = value;
            if(this.hasEventListener("sourceChange")){
                 dispatchEvent(new Event("sourceChange"))
            }
        }
    }
    

    Are you have more optimization???

    I think adobe binding – it’s powerful tool’s, special if you use BindUtils class.

  12. Posted on March 6, 2009 at 5:00 pm by xtyler

    wolfroma – glad you brought this up. Because property changes are so universal, any optimizations can go a long way. Using PropertyEvent’s dispatchChange has higher performance than 1) creating an Event object and 2) dispatching that Event object when nothing is listening. Everywhere.

    With the sheer number of properties that are Bindable compared to actual Bindings, this single change makes data binding possible in complex systems.

    Flex’s PropertyChangeEvent also has the static method, but without the optimization benefit. This code is auto-generated by the Flex SDK and so is never questioned. Flex’s BindingUtils works fine and is convenient. My goal is to provide something smaller, faster and weak-referenced in response to the concession, “data binding is too slow for larger applications”.

    It would be great if these techniques were adopted as a standard and available through a convenient workflow like Adobe’s data binding. For now it’s a little more effort, so use it where it makes sense for you.

  13. Posted on March 12, 2009 at 8:42 am by Jakub Galas

    Thanks a lot! Somehow I’ve made an assumption that the default Flex binding uses weak references (after all – that would be quite logical, right?). Huge memory leaks in my app have proven me wrong. Your solution helped me to cope with that to some degree.

    I’ve noticed some issues in your binding though:

    Let’s say you have a control that displays some complex data. An object can be assigned to it’s property, let’s call it personData. You want to bind something with some internal property of the object and get it refereshed each time a new objects gets assigned to personData:

    Bind.addBinding(this, ‘cityLabel.text’, this, ‘personData.address.city’);

    This will usually throw an error if data is not set yet (is null). A little tweak in your code seems to fix the problem – just check if source is not null in Binding::bindPath (Binding.as line 244):

    if(source != null && !(prop in source) ) {

    I suppose that after a reference to an object is assigned to data, sub-objects don’t get the property change listener attached, so internal changes inside data won’t be detected… Or am I wrong?

    Another problem is event priority. We have an object that has a List object inside it.

    … and you have a property bound with selectedItem of the list:

    Bind.addBinding(this, ‘mySelectedItem’, myList, ‘selectedItem’);

    if you read mySelectedItem inside the handleChange() function, it should be equal to myList.selectedItem, but it still holds the previous value. I tried to use eventPriority of EventPriority.BINDING in addEventListener calls inside Binding.as, but it doesn’t seem to help, so I think the problem is more complex.

    Btw – I’ve noticed, that you don’t useWeakReference in addEventListener – is that ok?

    Thanks again for posting your code.

  14. Posted on March 12, 2009 at 9:31 am by xtyler

    Jakub,

    Great comments, thanks! The fix for checking if source is null was implemented in the repo a while ago, I have yet to update the downloads (sorry).

    I’m not sure about the binding priority problems, but that’s excellent feedback – I’ll implement a higher-priority for bindings. The best test-case to check whether the bug is in Flex’s List or Flight’s Binding is to swap it out with Flex’s BindingUtils and see if it updates properly.

    Where binding is listening to an object’s property-changes, I purposefully don’t use weak-referenced event listeners. Theoretically the object won’t leave memory without notifying the binding through a dispatched propertyChange event. In practice however there is no guarantee that an object dispatches property changes (defeating binding at that point, but sometimes necessary) – do you think it would be safer to have even those listeners weak-reference? There is a slight performance hit over many weak-referenced listeners on the same IEventDispatcher, but probably not enough to be concerned.

    thanks again for the feedback!

  15. Posted on April 15, 2009 at 5:24 pm by Josh McDonald

    Nice, I’ve been planning to do something long these lines, but hadn’t gotten around to it yet. Looking forward to seeing more of Flight.

  16. Posted on May 27, 2009 at 6:46 am by Martin Collett

    I seem to be having trouble sorting my namespaces out – I’m getting an error ‘could not resolve to a component implementation. I’ve added ‘xmlns:flight=”flight.*”‘ to my top level tag (TitleWindow) and I have flight-framework.swc in my libs folder – any ideas? I’m just trying to use Bind at this point, not the whole framework.
    Regards, Martin

  17. Posted on May 27, 2009 at 6:48 am by Martin Collett

    ah – the xml got stripped out of the error message in my post, replaced with underscores below:
    Could not resolve _flight:Bind_ to a component implementation
    Thanks

  18. Posted on May 27, 2009 at 10:55 am by xtyler

    Martin,

    The xml namespace is xmlns:flight=”http://flight.flightxd.com/2009″

    It’s supposed to auto-complete for you in the Flex Builder environment, sorry if it’s given you much trouble.

    Let me know if that works for you.

  19. Posted on May 28, 2009 at 1:39 am by Martin Collett

    Brilliant, thank you – fixed. I think I filled in the xmlns myself first, didn’t give Flex a chance to do it for me – will watch out for that next time.
    I’ll let you know how I get on, Bind looks to be eactly what I need. I have a windowing app that crashes due to Binding causing massive memory leaks when I open and close windows,
    Thanks again, Martin

  20. Posted on July 12, 2009 at 5:00 pm by viatropos

    Hey man,

    How much faster/better performing is this custom binding than traditional Flex binding? 2x, 5x, 10x? If I have 1000 items in an ArrayCollection all changing values at once, will it prevent the application from temporarily freezing?

    Thanks for the info,
    Lance

  21. Posted on July 21, 2009 at 8:23 am by xtyler

    There have been enough changes/improvements since this post that I’ll write an update on this topic and provide some tests and statistics. I don’t think you’ll see a huge difference, especially over a trivial 1000 items. The Flex binding is still fast, coded on AS3, but it uses more memory and isn’t weak-referenced (Garbage Collection Friendly). Both solutions are tied into the Event Dispatching system.

  22. Posted on August 23, 2009 at 9:40 pm by viatropos

    One more thing: Binding and Tweening. Animations run in Flash/pure Actionscript are MUCH faster/smoother than the SAME animations run in Flex. This is presumably from both Binding and invalidation calls.

    For example, if you tween “alpha”, “x”, and “y” of a 500×500 Panel for 1 second, that can dispatch 50+ events, plus make a billion invalidation calls. If you do “setActualSize” for resizing (which they recommend), that’s another 3 events, so you can have in a single tween: ‘alphaChanged’, ‘xChanged’, ‘yChanged’, ‘widthChanged’, ‘heightChanged’, ‘resize’… every frame! On most computers other than the newest newest, or the ones we soup up, they chop through 2-4 frames of the animation. Terrible. I think it’s from all the binding going on which you don’t need.

    Question is, is Flight ready to handle that problem? It seems like it just about is, if you could put in there a “suspendBinding” method that we could set when running our effects and tweens, that would suspend binding events temporarily. That way I can run animations with zero binding events (when I don’t want them, which is almost always), and zero invalidation calls (some of the time).

    Any thoughts?
    Lance

  23. Posted on August 24, 2009 at 8:19 am by xtyler

    Current Flight binding does not have a “suspend binding” feature. But if nothing is bound to a property then the propertyChange event is never created and dispatched. This is one of the best system-wide improvements over Adobe’s binding, where instantiating a new object, the event, and then dispatching can add up.

    Recently I’ve been interested in revisiting the binding solution with a completely new method of updating bindings outside of the event flow. This means that any object could be bindable, not just IEventDispatchers, and it would also mean further speed improvements. The only downside to a new solution like this is that it wouldn’t be compatible with Flex at all, where the current binding is seamless.

    Overall I think tweening performance issues stem from the Flex invalidation cycle. Binding in Flex isn’t slow enough to be noticeable unless you’re doing many thousands of property changes in the same thread. Of course that is only taking the binding system into account, not any of the Flex code that responds to some of these property changes.

  24. Posted on August 25, 2009 at 11:18 pm by viatropos

    Here’s some stats on the performance increases of just adding that “hasEventListener” business.

    http://forums.adobe.com/message/2204490#2204490

    Cheers,
    Lance

  25. Posted on August 26, 2009 at 8:31 am by xtyler

    Quote from cited article:

    “so it looks like just adding that conditional statement to check for the event listener is kind of expensive. But it’s only a 2x performance hit instead of ~7-8x for dispatching an unnecessary event…”

    Most events go unlistened to, considering all the property changes and other events on all DisplayObjects and EventDispatcher’s in the system. This check saves significantly in overall performance of any system, while its minimal cost goes unnoticed.

  26. Posted on April 30, 2010 at 10:28 am by p48l0

    Found the error / bug ? mabe i have a bad setup or something, this line dosen´t work:

    propertyCache[metadata][value] = propertyCache[value].(child(“metadata”).(@name == metadata).length() > 0);

    but this one does:

    propertyCache[metadata][value] = propertyCache[value].(child(“metadata”).(@name == “Bindable”).length() > 0);

    this is from source code: flight.utils.Type

    Someone knows why is this?

  27. Posted on April 30, 2010 at 1:37 pm by xtyler

    This is a compiler error, if you rename the ‘metadata’ local property to ‘meta’ for example it will work great once again.

  28. Posted on May 5, 2010 at 8:15 am by Fyodor

    Does it work with dynamic objects like ObjectProxy? I’m using it as a Map or associative array.

    I’m binding to an ObjectProxy field and it only works if the proxy already contains the field at the moment the binding is created.

    I’m using Flight 1.0 RC.

  29. Posted on May 24, 2010 at 2:32 pm by AS3 Binding without the Flex Framework | johnlindquist.com

    […] You can read more details about this custom binding here: http://www.xtyler.com/code/177 […]

  30. Posted on November 9, 2010 at 3:30 pm by AS3 Binding without the Flex Framework | pv3d.org

    […] You can read more details about this custom binding here: http://www.xtyler.com/code/177 […]

The comments are closed.