Android SDK provides ability to run code in emulated environment called emulator. Its quite easy to start using it. But when it’s time to setup your favorite Continuous Integration system, a lot of issues with emulators start popping up.
The most critical ones is how to start the emulator and detect when its ready to be used to run some code. And how to kill/stop emulators reliably.
In this post I’d like to share some ideas I’ve come across and that seems to work stable enough.
Recently I was playing with one Android Market feature that gave me some interesting results and exposed some rules of this behavior. But more on this later.
In previous two parts I tried to describe how to correctly use background threads in Activities. I’ve pointed out that developers should be very careful when implementing background threads that should survive configuration changes, and described some pitfalls if this approach is taken.
I haven’t mentioned one alternative solution though – Fragments. The Fragments framework make things easier for many use cases. Also fragments may have no UI and represent some background task. This perfectly describes background task scenario.
Also each fragment can mark itself as “retainable”. This means that fragment’s lifecycle function onDestroy() is only called when Activity is actually being destroyed “forever” (as opposed to scenario when Activity is destroyed to be immediately re-created as during configuration changes). As soon as fragment calls setRetainInstance(true) it can rely for onDestroy() to be called only in those cases when background task should be cancelled (as opposed to Activity based implementation where developer should detect cases of configuration changes and allow background task to run in this case, and cancel task in other cases). This greatly simplifies things. Of course, no parent Activity references should be kept after onDetach() is called to avoid memory leaks.
I’ve created AsyncTaskFragment that echoes functionality of AsyncTask. It actually uses AsyncTask to run background task. But additionally AsyncTaskFragment knows when to cancel task, and when task should be left running (as during configuration changes).
The AsyncTaskFragment code and a simple example that uses it can be found here.
In my previous post I described three different scenarios which result in Activity’s destruction via calling onDestroy(). I also concluded how background threads should be managed in such conditions:
- Cancel all background threads when activity is finishing.
- Cancel all background threads when activity is being destroyed to reclaim resources.
- Do not use android:configChanges to help background threads surviving configuration changes.
The only scenario that was not covered in my previous post was how to manage background threads on configuration changes (assuming we agreed that android:configChanges should not be used). In this post I will describe two possible options:
- Cancel background thread when activity is destroyed due to configuration change.
- Keep background thread alive across configuration changes, thread reference can be passed between Activity instances using onRetainNonConfigurationInstance() functions.
Activities have well defined lifecycle and documentation covers how Activities should behave in great detail. Activity component starts its lifecycle when onCreate() is called and after onDestroy() returns this component is considered dead.
Android never allows same activity java object to go through several component lifecycles. In other words – one Activity java object goes trough exactly one Activity component lifecycle. Android is responsible for instantiating java object and abandons java object just after onDestroy() returns. When activity should be created again, new java object is instantiated and component lifecycle starts all over again.
Android has four primary components: Broadcast Receivers, Content Providers, Services and Activities. Each of these components has well defined lifecycle. These lifecycles are described in several first articles in Android Reference Documentation, and it’s considered one of the most important things each Android Developer should know. In this article however I’ll talk about what is usually referenced in documentation as “entire lifetime” of the component. In this post I’ll use “lifetime” in the same meaning as “entire lifetime” is used in Android Reference Documentation.
[Entire] lifetime - is time between moment when Android OS considers component to be constructed and moment when Android OS considers component to be destroyed. Let’s reference to components that have been constructed but not yet destroyed as to “alive” components.
Android applications support so called asset files. These are regular files located at `/assets` folder that are compiled into .apk file and can be accessed later at runtime. These files have no restrictions on inner format.
Also android supports custom files in `/res/raw` folder. Here are main differences between `/res/raw` and `/assets’:
- Files located in `/res/raw` have unique identifies generated for them in form of R.raw.filename. This imposes file name restrictions, they should not contain symbols that are not allowed in Java identifiers.
- All files inside `/res/raw` are subject for resource overlay.
- To access files in `/res/raw` you have to know resource id. You can’t access file in `/res/raw` without knowing its resource id (as far as I know there is no built-in API for this). While files located in `/assets` can be discovered dynamically using AssetManager.list().
- Custom directory tree can be placed inside `/assets` (though there is restriction on maximum path length). But files inside subdirectories of `/res/raw` are just ignored (i.e. /res/raw/subdir/file, where file will be ignored).
In most cases `/res/raw` will suffice, but in some cases `/assets` is the only way to go.