Working With Persistent Data in AIR

Why care about caching data on the client? There are 3 types of apps out there: Thin Client (HTML/JavaScript to web browser), Thick Client (Word, Excel, etc), Smart Client (RIA, a hybrid between the thick and the thin). Thin client and smart client both allow ease of deployment, but offline capability and access to hardware resources is problematic for the thin client.

AIR allows web technology to be deployed directly to the desktop.  Flex, flash, PDF, HTML, JavaScript, CSS, Ajax.  Always starts with a root document (HTML or SWF). HTML may contain PDF or SWF. Both have renderer, VM, and DOM.  Code between the VMs can interoperate.  All can be display in native OS chrome. And you can persist data locally (hence this preso!).

Storage models: Local shared objects, encrypted local store, file system, embedded SQL database.

Local shared objects. There are in package flash.net.*.  Used to serialize memory resident data structures. Runs in synchronous mode. This is a monolithic storage model. So it is fine for writing huge amounts of data, but when going to retrieve a single entry out of thousands, can take a proportionately long time.

Encrypted local store. In package flash.filesystem.*. Used to store sensitive data. Runs in synchronous mode also. All data is serialized using ByteArray. So it’s like blob storage with keys. A ByteArray is like an in-memory stream of information. So you take an array, put it in a ByteArray, then add the ByteArray to the encrypted local store. This encrypted local store is just this space that is available to you based on the application and user.  And it is faster at accessing the record you want. But the point isn’t that it’s faster at accessing records; the point is that it is doing security to make sure no one can read it without authorization.

File system. In package flash.filesystem.*. Provides random access to file system data. Can be asynchronous or synchronous. Two main components: File and FileStream. File represents a path to a particular file or directory. Completely OS-independent. FileStream does the actual work. Handles binary, object, text data.

Path handling: nativePath(), canonicalize(), resolvePath().

Cataloging: userDirectory(), desktopDirectory(), documentsDirectory(), applicationResourceDirectory(), applicationStorageDirectory(). File info (size, createDate, etc). copyTo(), moveTo(), etc. upload(), download(), send(), etc.  browse(), browseForDirectory(), etc.

FileStream implements the IDataInput/IDataOutput APIs. Can put binary data in — readBytes(), writeBytes(), readInt(), writeInt(), readDouble, writeDouble, etc.  Can do AMF3/AMF0 object serialization — readObject(), writeObject().

Embedded SQL Database.  Self-contained factor is nice. You have no external dependencies; it will work the same on any OS. Each database is stored completely within a single file. Zero setup. No configuration or administration required. It just starts working.  No server process required, no need for an administrator to create the database and user accounts. Handles transactions! Has a large capacity: Theoretical limit of over 2TB.

Package is in flash.data.*. Can be asynchronous and synchronous.  Uses SQLConnection and SQLStatement.

SQLConnection. Establishes connection state, configuration, transactions, schema access. In async mode, also creates its own background thread. So you can create five SQLConnections to run five database operations simultaneously.

SQLStatement. Does CRUD operations. Does parameters, paging, and custom result row data types.

The database functionality is VERY fast. Can work with thousands–millions–of records in less than 1 second. Data reads are even faster.

SQLConnection: open(), attach(). The attach() will allow you to run queries on tables across multiple databases. Comes in handy during certain circumstances. Handled not too unlike SQL Server, when you are referencing an external database in your SQL statements.

SQLStatement.getResult() — Returns a SQLResult object.

SQLResult: data() returns an array of objects that contain each row of the result. complete() indicates if you pulled the whole result set. lastInsertRowID() is self-explanatory. rowsAffected() is also self-explanatory.

Note! Putting data on disk via the database can be slow sometimes. Recognize that it is a 6-step process: (1) Acquire shared lock on the database. (2) Acquire a RESERVED lock on the database. (3) In-memory rollback journal is updated. (4) Contents of rollback journal are physically written to disk. (5) Acquire an EXCLUSIVE lock to the database. (6) Write all modifications for the DB to the disk.

At this rate, you’re probably only going to get 5-6 database transactions per second.  Maybe as many as 20 on a high-end box. So the key is to put MANY database operations all in a single transaction.

Transactions. SQLConnection manages the transaction. Use SQLConnection.begin() to start the transaction. Then, commit() and rollback() work as expected.

Storage classes. There are numbers (int/real), text, and blobs.

Affinity. Declaring a data type on a column determines the column’s affinity. You’re saying, “I want this field to be stored like this.” However, if you send a string to a field that should be a number, it won’t throw an error, it will just put it in there as a string.  Supports ActionScript affinities of boolean, date, int. Next beta should support XML, XMLList, Object, etc.  But currently, you can put arrays or objects in with blob, which will then treat it like a ByteArray.

Introspection. Access to the table/view, column, index, and trigger information, including the SQL used to create the entity. But you can do selective loading, i.e. I want to see the tables in this database. Just use SQLConnection.loadSchema(). Will return a SQLSchemaResult that has tables, views, triggers, and indexes. These are all arrays of objects with the associated values.

AIR Tips and Tricks

Window API. Lightweight windows are nice because they won’t appear in the taskbar/dock.  Utility windows don’t even have title bars and are nice for toolbars or similar things. You can have transparent windows so that the only content you’ll see is the Flex/HTML content you put in there.

Transparent windows require that you build your own functionality for window handling: Closing, minimizing, moving, resizing, etc. Now, when you use custom chrome, you can use Scale-9 in Flash/Flex to make it really easy to handle how resizing of the graphic works. You can do this with the <mx:canvas> tags in Flex.

HTML Control. WebKit is entirely integrated into the Flash Rendering Pipeline. Using the bridge, you can use functionality in either JavaScript or ActionScript and use it in the other environment: AS called within JavaScript; JavaScript called within AS.

File I/O. Full read/write access within the access provided the user running the OS. Have asynchronous and synchronous versions of the API. So quick and small file access can be done in a synchronous manner quickly, and longer access can be done asynchronously to maintain a quality user experience. Use standard native file dialogs: Save, select, select multiple, directory.

File I/O can save not just text/binary stuff, but you can read/write serialized AS objects. So, you can create an AS object with the info you need, then very rapidly write it out and have it very easy to read back in as that object.  Just use the writeObject() method of the filestream! Similarly, just use loadObject() when reading.  To make this work, you will need to add a tad of metadata to the object to make it work. Another caveat, the data will not be human-readable. But if human-readability is not important, this is much more rapid for writing a lot of data than it would be to save in some text or XML format and needing methods to write out and read back in the data.

Another solution could be to write this kind of data to the database via the database API. But sometimes that may be overkill, plus this can write files anywhere.

Database. A fully-embedded SQLite database engine. You’re accessing a local database. This is not for accessing remote databases. To do that, you’ll want a webservice that provides access to that database.  This database support is great for providing online/offline support. You can sync the information locally and then just utilize the local version.

One note: Every database function will be a separate transaction. If you have hundreds/thousands of database functions to perform, wrap them into one transaction so that the filesystem can do the file transaction more efficiently. In his sample, writing 1,000 database records took 2.3 seconds with no transactions; it took 0.1 second with transactions.

When handling database connectivity, you will: (a) Point to the database file. (b) If it doesn’t exist, do the code to create the database. (c) Do your database statements.

eBay’s Lessons Learned on AIR

eBay has an AIR app for managing your eBay activity. Launched during MAX 2007, even though it has been around since last year’s MAX. They learned things from it.

First, recognize that desktop apps have much more power than a web app. Why doesn’t everyone do them then? Desktop apps are a lot more expensive to build! Web apps have been getting more expensive as standards of quality rise, but they’re still cheaper than full-fledged desktop apps.

eBay built a fully-functioning prototype in just 3 months. Here are some lessons learned.

1. Start with a good foundation. They started the AIR app because they had already been building web services and API for eBay. So all they really had to do is build a UI. All the web service hype from 2002 was indeed hype, but now, five years later, the concept is finally coming together in a very key and important way. These web services are a great way to connect desktop apps to the web. Store your business logic in the web services that the desktop apps can access.

2. Design takes a long time. Of the first 3 months, six weeks were spent on design alone. Why? (a) AIR offers a lot of freedom. If it was more restrictive, it would have been more straightforward. :-) (b) They were pioneering things. There is not a prescribed manner to address a lot of the questions that come up. (c) Expectations have been raised for user experience.

3. Betas are really useful. I mean real betas, not marketing betas. They have thousands of users in the beta program and they get tons of feedback.

4. The most important AIR feature is… Freedom from constraints of the browser. No frustrating back button. No location bar.

5. Users don’t care about software platforms. A good platform, like AIR, just gets out of the way. Installation, auto software update, startup,  etc. Beta users haven’t complained about these kinds of things–the kinds of things that typically hinder Java apps or some other platforms.

AIR APIs

Here are some notes regarding some of the APIs for AIR that were showcased at the on AIR Bus Tour in Chicago.

Window API

Multi-window support. Transparent windows. Z-Ordering. All of the various aspects of OS windows can be applied to your AIR windows. When you use transparent windows with no chrome, the arrow will click through the transparent part of images as well. Nice.

File I/O

Reading and writing of files. No problem. Can launch native file dialogs. Can handle selection, selecting multiples, directories, etc. Async and sync versions of the APIs.  Would use async API if you’re doing very heavy processing.

Database Support

SQLite embedded database. Zero setup, uses a single file. Not for accessing remote databases. This is for using a completely local database. Easily storing data in a database format, but in a local manner.  He didn’t show any examples of this. :-(

Drag and Drop / Clipboard

System level drag and drop support is there! AIR app to AIR app, or AIR app to OS app and back again. Or to the desktop. Can use it for handling URLs, files, text, or even AS objects.  When marking something as draggable, you can assign one or many “transfer formats”. So when you drag an item to another app, if it doesn’t accept one data type, perhaps it will recognize another data type. For instance, if you have an image and a text transfer format, the receiving app may not like the image format, but it recognizes the text format, so it proceeds without a problem.

Service Monitoring

Handles the online/offline support. Will monitor the network interface for changes. Will detect not just network connectivity, but you can test access to a particular service. Do I have access to http://my.address.com/myservice?

Conclusion

These APIs work in JavaScript too because of the bridge, but it all works very well in Flex.  Daniel Dura was the presenter, and hit site at http://www.danieldura.com has a lot of AIR information.

  Theme Brought to you by Directory Journal and Elegant Directory.