Local Caching of Remote Images in AIR for Android
Posted on 2013-01-30 17:15 Bill Yuan 阅读(562) 评论(0) 编辑 收藏 举报转自:http://remotesynthesis.com/post.cfm/local-caching-of-remote-images-in-air-for-android
I was working on an application (some of which will be featured in the upcoming Adobe Edge) that used several images delivered by an API remotely over the web. When working with mobile applications where data is often being delivered by wireless 3G connections of varying signal strengths/speeds, downloading even small(ish) images can be costly and slow. The other thing that you may notice is that if an image component in your Flex "Hero" mobile application is bound to a remote URL, it will reload every time the view is reactivated - meaning you can incur that cost repeatedly. In my case I used your Xbox Live profile tile on the header of most of my applications pages so the delay was blatantly obvious as I pushed and popped views.
Thankfully, AIR for Android and thereby mobile Flex "Hero," has full access to the file API as you would on the desktop. Using the file API I was able to download and store the image locally and simply display the image from my local device storage, eliminating the delay on all subsequent loads - even when the application is closed and reloaded. Here's how.
First of all, within my mobile View I declared a variable for my URLLoader class:
private var urlLoader:URLLoader = new URLLoader();
As I stated, in my case the remote image URL was being returned by an API call. Within the result handler for this call, I went ahead and added the following lines of ActionScript to begin the process of downloading the image using the URLLoader:
// since these images load slowly over phone, I will just load and cache them locally urlLoader.dataFormat = URLLoaderDataFormat.BINARY; urlLoader.load(new URLRequest(URL_OF_IMAGE)); urlLoader.addEventListener(Event.COMPLETE,tileLoaded);
As you may notice, I have added an event listener for when this download is complete. Let's take a look at the handler for this, which is where we get into the File API:
protected function tileLoaded(event:Event):void { var tilefile:File = File.applicationStorageDirectory.resolvePath("tile.png"); if (tilefile.exists) { tilefile.deleteFile(); } var fileStream:FileStream = new FileStream(); fileStream.open(tilefile, FileMode.WRITE); fileStream.writeBytes(urlLoader.data); fileStream.close(); myImageComponent.source = tilefile.url; }
The specifics of the File API in AIR actually remain the same here as they would on the desktop. First, I create a reference to the file within the application storage directory. Next I delete the file if it already exists (not sure this is necessary actually). Next I write out the image to disk using a filestream. Once this is complete, I change the source of the image component in my view to the locally stored image.
One thing I noticed in my testing was that binding to the local image using the normal AIR file prefixes or the above File.url property didn't seem to work on the phone (which is a Nexus One) even though it did in the simulator. I'm not entirely sure why that is and if that is the expected behavior on mobile, but this is why I manually set the source property - which works fine. However, this means that, assuming the image exists on disk, you will need to set this property when the view loads. I did this in the ViewActivate handler:
// see if we can just use a local copy of the tile var tilefile:File = File.applicationStorageDirectory.resolvePath("tile.png"); if (tilefile.exists) myGamerimage.source = tilefile.url;
In the end this technique worked great for handling the images I was pulling off this API. Depite the initial load time on the first time load, every time following loaded quickly, even when the application was closed or shut down completely. I was even able to display the cached version while I checked and loaded a newer version if one existed. The key is, the API's you were used to using in AIR still work on Android - and that's an amazing thing in my opinion.