In previous post I mentioned about project robomorphine. The component that I want to talk about in this post is called robomorphine-testrunner.
The robomorphine-testrunner is supposed to treat pains around automating tests, like starting and stopping emulators, running tests, collecting test results, etc. All this should be done in a stable and reliable way, so you could easily start running your tests on CI server.
In my experience Android SDK has many annoyances and instabilities. Sometimes even broken functionality that prevents some major scenarios (usually something related to emulators). This library is also supposed to include known workarounds for these issues (when possible), so the end-user doesn’t need to follow and fix their automation each time new version of SDK comes out (with new bugfixes and bugs included).
The core principles:
- It should be stable
- It should be configurable to meet complex requirements
- It should be simple to use
The last two points are contradicting, and configurability is considered a higher priority. Though simplicity of use is still important, and that’s why reasonable defaults are provided in many cases.
Several months ago I decided to start a new project. And since every project has to have a name, I spent some time thinking about it. And I came up with a name I really liked, so please welcome project “robomorphine”.
I even made a tag line that pretty much summed up what the project was about:
Morphine is primarily used to treat both acute and chronic pain. Robomorphine is created to treat Android pains.
But robomorphine is actually more of a meta-project. It will contain other sub-projects that are going to target different Android related areas.
And actually there are two sub-projects currently in the works: robomorphine-core and robomorphine-testrunner. There is nothing to announce about robomorphine-core yet, but robomorphine-testrunner is almost ready for release. I’ll give much more details about it a separate post.
I know it’s not much information. But the cool stuff is coming, so stay tuned.
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.