BetaDesigns( Blog ) Flex and Component Development

8Jun/120

Liquid-Photo only £0.69 this week!

Liquid-Photo for ios will be at the reduced price for this week only! Get it while you can. And please retweet or share with anyone you think would like the application.

Liquid-Photo

19May/120

Liquid-Photo Free This weekend ( 18 May – 21 May 2012 )

To celebrate my Liquid-photo website getting hacked i have decided to give away Liquid-Photo for iOS for free this weekend. Please download and let me know what you think about the application. Also please retweet, facebook or otherwise let everyone know about the offer. You can download it here for free

2Nov/110

Performance Improvements and Optimisations

To kick off our series on how we optimised and improved Liquid-Photo 4.0 I wanted to first discuss some of the issues we were facing and why.
When starting out to build Liquid-photo we decided to use ActionScript and the Air runtime. This decision was mostly due to our experience in ActionScript and with the Air runtime as a whole, however it also has the added benefit that we can, if we wish port the application more easily to other platforms such as iOS and Android.

Whilst development of the first iteration of the application was quick and we were able to get a finished application onto the Blackberry AppWorld within a month. However we soon started receiving information from customers that the application was not running at an acceptable frame rate. This lead us to re-look at the way in which the application was designed and how we could go about improving the speed and responsiveness of the application.

We are going to cover several topics over the next few days to highlight how we improved the newest release of Liquid-Photo.

  1. Persisting Data with parsley
  2. Optimising ItemRenderer's for TileLayouts
  3. Using GreenThreads to improve user interaction

Once these posts are finished we will also discuss some of the other techniques used for creating the application.

We hope that you find some of these tips useful.

Filed under: Flex, liquid-photo No Comments
2Nov/110

Persisting Data with parsley

The first iteration of Liquid-Photo did not save any user data, once it was closed that was it every setting had to be re-set on startup and the users images all had to be re-loaded. This obviously was not an ideal solution. In comes Parsley Persistence Capabilities.

For those that do not know what Parsley is a brief explanation may be in order. Parsley in simple terms is an ActionScript IOC(Inversion Of Control) Dependency Injection Framework. That said it has a wealth of features that make it ideal for any size project from the simplest PlayBook Application to some of the largest Enterprise Applications in the world and I personally have used it on both.

I will not go into how to setup a project using Parsley as there are lots of examples and documentation over at the Parsley website, what we will look at here is firstly how to save some simple users settings using the default Parsley persistence mechanisms and then a slightly more complex version in which we show how to save the current application view state.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
 
package com.liquidphoto.settings.user
{
    public class EffectSettings
    {
        //----------------------------------------------------------------------
        //
        // Public Properties.
        //
        //----------------------------------------------------------------------
 
        [PublishSubscribe(persistent="true", objectId="effectSettings.playEffects")]
        [Bindable]
        public var playEffects:Boolean;
 
        [PublishSubscribe(persistent="true", objectId="effectSettings.intensity")]
        [Bindable]
        public var intensity:Number;
 
        [PublishSubscribe(persistent="true", objectId="effectSettings.initialised")]
        [Bindable]
        public var initialised:Boolean;
 
        //----------------------------------------------------------------------
        //
        // Public Methods.
        //
        //----------------------------------------------------------------------
 
        [Init]
        /**
         * Initialise the settings.
         * This will be automatically called by Parsley
         * when this class is created. 
         */
        public function init():void
        {
            if (!initialised)
            {
                reset();
            }
        }
 
        /**
         * Reset the settings to the initial values. 
         */
        public function reset():void
        {
            play = true;
            intensity = 6;
            initialised;
        }
    }
}

Ok so what is going on here? Firstly we setup some public properties that we want to persist to the local shared object on the device. We mark each one as [Bindable] and also add a Parsley [PublishSubscribe] metadata tag. By setting the persistent="true" value on the tag we tell parsley that every time this value changes persist that change to the local shared object and the next time the application is started parsley will then populate this variable with the value it persisted perviously. The important thing to note here is the use of the objectId property, You must set this property to something unique if you are persisting simple types like Numbers, Booleans etc.. If you do not then every variable that persists the same type of value without an objectId will be replaced with the last saved value.
For example the two variables initialised and playEffects above both have Boolean values, if they did not have any objectId properties then whenever the playEffects value was changed and persisted that value would also be set on the initialised value the next time the application was started.

Next is the Parsley [Init] tag which gets called as soon as Parsley instantiates this class, The first time this is run the initialised value is false so it runs the reset method which sets up our applications default settings, when it sets these they are then persisted to the Shared Object so the next time the application runs the same values are set on the values by parsley. This means that if the user changes any user settings the bindings will be fired and Parsley will persist the users changes for the next time the user opens the application.

Finally we have a reset method so that we can reset the values back to the defaults if we need to.

Now lets look at a more complex situation persisting user views.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package com.liquidphoto.persistence
{
    import mx.utils.NameUtil;
    import flash.utils.getDefinitionByName;
 
    public class NavigationPersistence
    {
        //----------------------------------------------------------------------
        //
        // Constants
        //
        //----------------------------------------------------------------------
 
        private static const LOG:Logger = LogContext.getLogger(NavigationPersistence);
 
        //----------------------------------------------------------------------
        //
        // Public Properties.
        //
        //----------------------------------------------------------------------
 
        [Inject]
        public var navController:NavigationController;
 
        [PublishSubscribe(persistent="true", objectId="navigation")]
        [Bindable]
        public var persistedViews:Array;
 
        //----------------------------------------------------------------------
        //
        // Public Methods.
        //
        //----------------------------------------------------------------------
 
        [Init]
        public function init():void
        {
            //Setup our application close handlers.
            setupCloseHandlers();
            //If we have some persisted data try to push it to our navigation controller.
            if (persistedViews && persistedViews.length > 0)
            {
                var viewClass:Class;
                for each (var view:String in persistedViews)
                {
                    try
                    {
                        //Try to get our persisted view class
                        viewClass = getDefinitionByName(view) as Class;
                        navController.pushView(viewClass);
                    }
                    catch (error:ReferenceError)
                    {
                        LOG.fatal("Applicaiton persisted view could not be found! {0} Starting over from the begining.", view);
                        navController.pushView(SplashScreen);
                    }
                }
                LOG.debug("Rebuilding persisted views {0}", persistedViews);
            }
            else
            {
                //No views to persist so load our splashscreen.
                navController.pushView(SplashScreen);
            }
        }
        //----------------------------------------------------------------------
        //
        // Private methods. 
        //
        //----------------------------------------------------------------------
 
        private function setupCloseHandlers():void
        {
            //Listen for application exiting.
            NativeApplication.nativeApplication.addEventListener(Event.EXITING, nativeApp_exitingHandler);
        }
 
        private function nativeApp_exitingHandler(event:Event):void
        {
            var persistViews:Array = [];
            for each (var item:* in navController.stack)
            {
                persistViews.push(NameUtil.getUnqualifiedClassName(item));
            }
            persistedViews = persistViews;
            LOG.debug("Persisting views {0}", persistedViews);
        }
    }
}

So to begin with we setup a simple logger so we can see what classes we are persisting and pushing to our navigationController, ( Our NavigationController is a simple class that instantiates the views pushed to it and pushes them to the main application view ). Using the Parsley [Init] metadata, when this class is instantiated by Parsley we first setup our event listeners to detect for when the application is about to close, we could persist this data constantly as our application changed but for our use case we can simply do it as the application is closing.

If we now look at the nativeApp_exitingHandler() method we can see that we are simply building an array of class names and pushing them to the persistedViews array. Now if we go back to the init() method we can see that if there are persistedViews we loop through them pushing the classes to the navigationController, if one of the persisted views is invalid then we fall back to displaying our SplashScreen.

And that is all that is required to use Parsley for persisting our application state.

In the next post we will be discussing Optimising ItemRenderer's for TileLayouts and how we reduced the TileLayout render time from over 10 seconds down to less than 900 milliseconds!

29Aug/112

Liquid-Photo Version 3.1.33 Submitted to AppWorld

We have just submitted version 3.1.33 to the Blackberry AppWorld. This release addresses several issues that some of our users were experiencing and includes the following.

*Fixed Bugs
** Image scanning now performed in the background so that users with large numbers of photos can still use the application without having to wait for all images to be found.
** Increased small button hit areas to make them easier to select.

Please update if you have been having any issues.

Kind Regards
The Liquid-photo team.

28Aug/110

Liquid-Photo Version 3.1.32 Submitted to AppWorld

We have just submitted version 3.1.32 to the Blackberry AppWorld. This release addresses several issues that some of our users were experiencing and includes the following.

*Fixed Bugs
** Invalid images caused the application to crash this has now been fixed and the liquid-photo will now continue to load as well as alert the user about which images are corrupt.

Please update if you have been having any issues.

Kind Regards
The Liquid-photo team.