Paged list loaded from sqlite in Adobe AIR
During my recent work on the Adobe Evangelists Blogroll application I wanted to implement a lazy-loaded/paginated List component with data coming from a local SQLite database. The reason for this was, of course, a memory usage consideration. Adobe Evangelists Blogroll is a mobile application so I didn’t want to load all available Post objects for each selected blog at once. I wanted it to be loaded dynamically as the user scrolls through the list. It turned out this wasn’t really difficult but there were few gotchas that I wanted to share:
- You have to implement your own
IListcomponent that throwsItemPendingErrorwhenever the item requested withgetItemAtfunction is not available yet. Unfortunately the Flex SDK doesn’t come with one built-in, but the good news is that you can usePagedArrayListclass I created; its source code is available here
- Implement a
createPendingItemFunctionfor theAsyncListViewcomponent. This function gets called whenItemPendingErroris thrown and in our case serves two purposes. One is to trigger fetching the next page of rows from the database. It also returns aStringwith text that will be displayed temporarily in missing rows of theList. When that data gets fetched from the database those missing rows will be replaced with the loaded ones. - One gotcha for the previous point is that if you are using
SQLConnectionin synchronous mode you will have to start fetching rows in the next frame after the call to thecreatePendingItemFunctionfunction. That is why in my example I’m usingcallLaterto execute thefetchRowsfunction. This problem doesn’t arise with an asynchronous database connection. - The last gotcha is most likely a bug in the Flex SDK. It occurs when the
AsyncListView.listproperty is set before its list object is initialized and its length value is set. In that caseinvalidIndexerror is thrown inside of LinearLayoutVector. The workaround I came up with is that right after setting the length property,PagedArrayListdispatchesFlexEvent.INITIALIZEevent; the application logic should handle it and programmatically set theAsyncListView.listproperty to thePagedArrayListinstance. For reference I filed a bug in Flex SDK Jira.
Below you can find the source code that resolves the gotchas above. Also the whole Flash Builder project with paged list implementation is available here.
<?xml version="1.0" encoding="utf-8"?> <s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:helpers="com.riaspace.helpers.*" preinitialize="windowedApplication_preinitializeHandler(event)" creationComplete="windowedApplication_creationCompleteHandler(event)"> <fx:Script> <![CDATA[ import mx.collections.errors.ItemPendingError; import mx.events.FlexEvent; protected var conn:SQLConnection; protected const PAGE_SIZE:int = 50; protected function windowedApplication_preinitializeHandler(event:FlexEvent):void { // Creating inmemory database conn = new SQLConnection; conn.open(); // Creating data_tab table var createStmt:SQLStatement = new SQLStatement; createStmt.sqlConnection = conn; createStmt.text = "CREATE TABLE data_tab (value_col TEXT)"; createStmt.execute(); // Inserting 1000 records to the table var insertStmt:SQLStatement = new SQLStatement; insertStmt.sqlConnection = conn; insertStmt.text = "INSERT INTO data_tab VALUES (?)"; for (var i:int = 1; i <= 1000; i++) { insertStmt.clearParameters(); insertStmt.parameters[0] = "value " + i; insertStmt.execute(); } } protected function windowedApplication_creationCompleteHandler(event:FlexEvent):void { // STEP 1 - query rows count var stmt:SQLStatement = new SQLStatement; stmt.sqlConnection = conn; stmt.text = "SELECT count(*) as rowsCount FROM data_tab"; stmt.execute(); var result:SQLResult = stmt.getResult(); // STEP 2 - set PagedArrayList.length equal queried rows count pagedArrayList.length = result.data[0].rowsCount; // STEP 3 - fetch actual data starting from 0 offset (1st row) fetchRows(0); } protected function fetchRows(offset:int):void { // Fetch data rows with specified limit which is our requested page size // and offset passed as parameter var stmt:SQLStatement = new SQLStatement; stmt.sqlConnection = conn; stmt.text = "SELECT * FROM data_tab LIMIT :limit OFFSET :offset"; stmt.parameters[":limit"] = PAGE_SIZE; stmt.parameters[":offset"] = offset; stmt.execute(); var result:SQLResult = stmt.getResult(); if (result && result.data) { for(var i:int = 0; i < result.data.length; i++) { // Setting return row at offset + i position pagedArrayList.setItemAt(result.data[i], offset + i); } } } private function createPendingItemFunctionHandler(index:int, ipe:ItemPendingError):Object { // In case synchronous database mode is used fetchRows function should be called // after return from this function. With asynchronous mode fetchRows function can // be called directly. callLater(fetchRows, [index]); // Returning a message to display return "List items are being fetched from database..."; } protected function pagedArrayList_initializeHandler(event:FlexEvent):void { // NOTICE: this is a workaround for a Flex bug that causes invalidIndex error // in LinearLayoutVector. It all works well when asyncListView.list property // is set after pagedArrayList is initialized and its length property is set. asyncListView.list = pagedArrayList; } ]]> </fx:Script> <fx:Declarations> <helpers:PagedArrayList id="pagedArrayList" initialize="pagedArrayList_initializeHandler(event)" /> </fx:Declarations> <s:List width="100%" height="100%" labelField="value_col"> <s:AsyncListView id="asyncListView" createPendingItemFunction="createPendingItemFunctionHandler" /> </s:List> </s:WindowedApplication>
Adobe Evangelists Blogroll preview
Today I’m officially announcing my new mobile application called Adobe Evangelists Blogroll. This is a simple RSS reader type of application that aggregates blog feeds from my fellow Adobe Evangelists. I’ve developed it with a preview release of Flex Hero SDK and it works on all Android devices that can handle AIR runtime. The app is available in Android Market if you look for “Adobe Evangelists Blogroll“.
What I’m also really excited about is that I managed to repackage it into a bar file and run it on BlackBerry PlayBook emulator without doing even single change to the codebase. In the video below you can see it in action running on different devices and also on PlayBook emulator.
As I already mentioned it was built with preview release of Flex SDK and also the app itself is in beta so it may have some quirks here and there. If you have any suggestions, comments or found some bugs you can contact me through this form.
Few screens of the application (running in landscape & portrait orientation and on playbook):
Flash StageVideo API performance overview
As you may know, today Adobe released a beta version of upcoming Flash Player 10.2. This release brings few really cool features especially in the field of Flash video. In the recording below I demonstrate really incredible performance gains that you can have with new StageVideo API, which gives you full GPU acceleration of video content.
I just passed Flex 4 Adobe Certified Expert Exam
Today I passed Flex 4 ACE exam. I made a very decent score of 93% with following distribution in the exam sections:
- Creating a User Interface (UI) 85%
- Flex system architecture and design 100%
- Programming Flex applications with ActionScript 100%
- Interacting with data sources and servers 87%
- Using Flex in Adobe AIR 100%
To prepare for the exam I used Attest3, I went through the mock tests 3 or 4 times and at the same time I used Flex 4 help and ActionScript 3 docs as a reference. I encourage anyone to take the exam as it gives you a good overview of your Flex/AIR knowledge.
Video with an un-framework overview
I wanted to share a video recording with an un-framework overview. This simple library has evolved a little bit from my previous post but I expect it will stay in this form for good
I don’t think it can evolve to anything more sophisticated but I hope that it will serve as an inspiration to others when building their own sets of helpers. I plan to use it solely as a substitue for my favorite DI frameworks when doing mobile Flex development.
UnFramework – or how to work without any frameworks
Those who know me or at least subscribe to my blog know that I’m a big fan of Flex/AS3 frameworks. At this year’s Adobe MAX conference I even had my own session where I covered five major DI frameworks. Usually these frameworks provide a lot of productivity features and helpers like: IoC/DI, Event/Messaging bus, implementation of some architectural or design patterns (MVC, Command…), and many others. But what happens if we can’t or don’t want to use any of these frameworks?
Extending model objects with ObjectProxy class
Recently I was looking for an easy way to extend my existing model objects with additional properties. The problem I had was that there was no option to mark these model classes as dynamic. What I came up with was a solution that uses the ObjectProxy class that comes with Flex. ObjectProxy essentially is a class that allows you to track property changes of its wrapped object. So what I also got with this approach was an ability to register a PropertyChangeEvent handler with my model objects.
The snippet below shows how I extend my User class object with an additional selected property. This is a view specific property so it wouldn’t really be a good practice to do it directly in the model.
// Wrapping each user into ObjectProxy with selected additional property selected var userProxy:ObjectProxy = new ObjectProxy({user:user, selected:false}); // Registering event PROPERTY_CHANGE handle userProxy.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, userProxy_propertyChangeHandler);
Below is a reason why I needed all that and how it works in practice; you can right-click the example to view the source code. BTW: If you are looking for a simple and quick way to have a dynamic Checkbox List this a way to go.
Another thing that the ObjectProxy class can resolve is a very common warning that occurs when you try to bind to not bindable properties: warning: unable to bind to property 'foo' on class 'Object' (class is not an IEventDispatcher).
Slides and source code of my Adobe MAX 2010 presentation
Adobe MAX 2010 is over and I’m heading back to Poland. Before I get on the plane I wanted to post my presentation deck and the source code of a demo app that I used to cover the DI frameworks. I also hope to post the session recording as soon as it gets to Adobe TV. BTW this years MAX was really awesome!
Building NativeApplicationUpdater custom UI
After I published the NativeApplicationUpdater library I received a lot of questions how to display a UI showing download and install progress. Unfortunately NAU doesn’t come with a built-in UI yet
So I decided to put together this short blog post to explain how you can build it yourself. Below you can see how the demo app with the custom UI looks (project source code is available here in SVN):

Below is snippet of code that you can examine to better understand how to build your own updater UI:
<?xml version="1.0" encoding="utf-8"?> <s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:updater="http://updater.riaspace.com/"> <fx:Script> <![CDATA[ import air.update.events.DownloadErrorEvent; import air.update.events.StatusUpdateEvent; import air.update.events.UpdateEvent; import mx.controls.Alert; [Bindable] protected var downlaoding:Boolean = false; protected function isNewerFunction(currentVersion:String, updateVersion:String):Boolean { // Example of custom isNewerFunction function, it can be omitted if one doesn't want // to implement it's own version comparison logic. Be default it does simple string // comparison. return true; } protected function updater_errorHandler(event:ErrorEvent):void { Alert.show(event.text); } protected function btnCheckNow_clickHandler(event:MouseEvent):void { // First initialize NativeApplicationUpdater updater.initialize(); } protected function updater_initializedHandler(event:UpdateEvent):void { // When NativeApplicationUpdater is initialized you can call checkNow function updater.checkNow(); } protected function updater_updateStatusHandler(event:StatusUpdateEvent):void { if (event.available) { // In case update is available prevent default behavior of checkNow() function // and switch to the view that gives the user ability to decide if he wants to // install new version of the application. event.preventDefault(); currentState = "updaterView"; } else { Alert.show("Your application is up to date!"); } } protected function btnYes_clickHandler(event:MouseEvent):void { // In case user wants to download and install update display download progress bar // and invoke downloadUpdate() function. downlaoding = true; updater.addEventListener(DownloadErrorEvent.DOWNLOAD_ERROR, updater_downloadErrorHandler); updater.addEventListener(UpdateEvent.DOWNLOAD_COMPLETE, updater_downloadCompleteHandler); updater.downloadUpdate(); } protected function btnNo_clickHandler(event:MouseEvent):void { currentState = "mainView"; } private function updater_downloadCompleteHandler(event:UpdateEvent):void { // When update is downloaded install it. updater.installUpdate(); } private function updater_downloadErrorHandler(event:DownloadErrorEvent):void { Alert.show("Error downloading update file, try again later."); } ]]> </fx:Script> <s:states> <s:State name="mainView"/> <s:State name="updaterView"/> </s:states> <fx:Declarations> <updater:NativeApplicationUpdater id="updater" updateURL="http://riaspace.com/native-application-updater/update-1.1.xml" isNewerVersionFunction="{isNewerFunction}" initialized="updater_initializedHandler(event)" updateStatus="updater_updateStatusHandler(event)" error="updater_errorHandler(event)" downloadError="updater_errorHandler(event)" updateError="updater_errorHandler(event)" /> </fx:Declarations> <s:Button id="btnCheckNow" label="Check for updates" includeIn="mainView" horizontalCenter="0" verticalCenter="0" click="btnCheckNow_clickHandler(event)"/> <s:HGroup verticalCenter="0" includeIn="updaterView" horizontalCenter="0" verticalAlign="top"> <s:BitmapImage source="@Embed(source='/assets/icon128.png')" /> <s:VGroup width="100%" horizontalAlign="center"> <s:Label text="New version ({updater.updateVersion}) is available." /> <s:Label text="Do you want to download it and install?" /> <mx:ProgressBar id="prgBar" source="{updater}" label="Downloading %3%" visible="{downlaoding}" /> <s:HGroup> <s:Button id="btnYes" label="Yes" click="btnYes_clickHandler(event)" /> <s:Button id="btnNo" label="No" click="btnNo_clickHandler(event)" /> </s:HGroup> </s:VGroup> </s:HGroup> </s:WindowedApplication>
NativeApplicationUpdater version 0.4 released!
I just posted a new version (0.4) of the NativeApplicationUpdater library. It fixes some minor bugs and removes a workaround for the different URLStream events sequence between Win OS and other OSes.
Stay tuned for my next post that explains how to build NAU custom UI.




