Android Dev Tips - How to get static Application Context from anywhere?
Everyone is facing with the problem of accessing Context instance from methods, which aren’t logically linked with Activity or Service.
It may be needed for accessing independent resources, like strings or files from assets folder. Sometimes it may be inconvenient to initialize and keep additional variable with the static context.
There’re lot of questions on StackOverflow about this. Today I want to share my experience of handling such kind of problems.
class Foo {
boolean flag;
String bar() {
int stringId = flag ? R.string.yes : R.string.no;
return context.getString(stringId);
}
}
So, the first solution is just to place context variable in target class. Unfortunately it may affect lot of related code, we need to pass Context reference across all of dependent classes.
class Foo {
Context context;
boolean flag;
Foo(Context context) {
this.context = context;
}
String bar() {
int stringId = flag ? R.string.yes : R.string.no;
return context.getString(stringId);
}
}
Other guys try to add public static method to Application class and access it from anywhere. I don’t like this approach because of additional dependency to custom Application class. In case when you’re working on library, it’s inappropriate at all.
Well, my solution is to create standalone class AppHolder which will be able to provide us Application Context without any additional steps.
public class AppHolder {
private static final android.app.Application APP;
public static android.content.Context getContext() {
return APP.getApplicationContext();
}
static {
try {
Class<?> c = Class.forName("android.app.ActivityThread");
APP = (android.app.Application) c.getDeclaredMethod("currentApplication").invoke(null);
} catch (Throwable ex) {
throw new AssertionError(ex);
}
}
}
This code access hidden field from OS class via Reflection API. Of course, it’s not good and it may be risky in theory, but it works well on practice! This code is executed only once per lifetime of app. Static reference to Application instance is cached in static final variable, nobody will re-write it.
If you don’t like to use Reflection API at all, you may adapt this solution on your own choice.
And now we can access static application context from anywhere.
class Foo {
boolean flag;
String bar() {
int stringId = flag ? R.string.yes : R.string.no;
return AppHolder.getContext().getString(stringId);
}
}
You may find source code at the end of this post or you can use method Global.getContext() from my Xdroid library. This library is still “in progress”, but it was tested already in real projects.
dependencies {
compile 'com.shamanland:xdroid-core:0.3.0'
}
Thanks for reading! Watch for updates.
Source code
AppHolder.java
public class AppHolder {
private static final android.app.Application APP;
public static android.app.Application getApp() {
return APP;
}
static {
try {
Class<?> c = Class.forName("android.app.ActivityThread");
APP = (android.app.Application) c.getDeclaredMethod("currentApplication").invoke(null);
} catch (Throwable ex) {
throw new AssertionError(ex);
}
}
}