Android contexts and singletons

google android context and singleton class and application relaunchUnderstanding contexts in android correctly is every developers nightmare. This article highlights some of the findings which will help you understand contexts in android a little better. This article is more useful if you follow a singleton pattern in your app.

The general rule of thumb when using contexts is to use the activity’s context whenever possible. I would like to highlight some of the issues when I followed this rule blindly without understanding contexts correctly. In one of the projects, a lot of singleton classes were used to maintain states of different components used throughout the app. For e.g, DatabaseManager was a singleton which was a single point of entry to perform all the DB operations. Now, there are lot of developers who hate using singletons in java, because it gets abused quite a lot and make is difficult to reuse/separate components if required. Read this for more info.

Anyways, we ended up using a singleton pattern throughout our app. But some of the singletons required to use the android context for initialization. So the first thing which came to our mind was to initialize these singletons on app startup.

Mistake 1

The first mistake we did was we used the launcher activity’s context to initialize our database (singleton class) and any other activity which launches later assumed that the database was initialized and perform CRUD on it. This worked quite well for a long time because our launcher activity would only be killed if the app is exited, not otherwise. But we later realized that our app was crashing whenever we opened our app after keeping it minimized it for a long time. The stack trace showed a nullpointerexception in SQLLite code. But the biggest issue was to reproduce this error consistently during development. Most bugs get closed because the developers cant reproduce the bug. So our first task was to find a way to reproduce it consistently, so that we can verify our fix.

The way to reproduce this bug was to enable “Dont keep activities in background” found in Android ICS’s developer options.

Due to this setting, the activity’s context would get destroyed as soon as you go to a new activity, which means that the database which we initialized with the launcher activity’s context is not valid as soon as we leave the launcher activity.

Mistake 2

That leads us to our second mistake. To fix the previous crash, what we did was to use android’s getApplicationContext method to initialize our singletons with the application’s context instead of the activity one. So it was a one line change that we did in the launcher activity.

We assume that this fixed the issue completely because we could reproduce the crash before the crash and the after the fix our app did not crash in our dev environment.

But a few days later the same crash surfaced again. We were stunned that it happened again after fixing it.

After a few hours of pulling out hair, what we realized was quite astonishing.

Our assumption that the launcher activity will always launch first was wrong.

During a memory crunch, android first kills all the activities, but decides to keep singletons. Then when more memory is required, android kills everything altogether. But when android restores your app (due to the user opening it again), it will remember the activity stack. When this happens, the topmost activity will remain in the top even though the app itself was launched fresh. This was what had caused the crash. We were only initializing in the launcher activity.

Mistake 3

The third mistake we made was to do a quick fix for the previous crash. We stored the application context in another singleton. And in each activity we had a if block which checked if the the stored context is null or not. If null, we initialized our singletons with the application context. This approach did not give us any crashes as such. This is because our application context is alive as long as the app is alive. If our activity is destroyed, it doesnt matter since we used app context. If our app gets killed in the background and the user launches from a new activity, our check will re-initialize the singletons.

Looks like a good solution but what if we create a new activity and forget to add this check ? How do we ensure that we dont forget to do this as the app codebase evolves.

That leads us to the correct approach.

Solution

The correct way is to subclass the application. You can do it in the manifest file.

In the onCreate of the application class we can initialize the singletons. And since the onCreate of the application gets called before any of the activities launch and also gets called if the app gets killed in the background, its safe to perform any such operations here.

That solved all our issues related to contexts and singletons and we never had to worry about this issue.

Rule of thumb

From now on the rule of thumb I would follow is this:

“If the lifecycle of the object holding the context is same as the application lifecycle, then use application context. If the lifecycle is same as activity, then use activity context. If the life is greater than that of activity but less than that of the application, even then use application context”

We learnt it the hard way, I hope it helps our fellow android developers.

Incoming search terms:

One thought on “Android contexts and singletons

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>