Contents
Android Context in non-activity Class – The Secret of ContextWrapper
One of most frustrating issues I had to figure out when I’ve started to develop for Android was the Context.
Android Context in non-activity Class
Why there are several kind of Context? and more important – How can I call to system API method from a Class when all the important functions are available only from a Context class??
The problem
Let’s take this function inside activity for example (test for AirPlane Mode),
Where isAirPlaneModeOn() is using the getContentResolver() which is Context.method:
public class MyActivity extends Activity { ... public boolean isAirplaneModeOn() { return Settings.System.getInt(getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0; } }
Or inside a service:
public class MyService extends Service { ... public boolean isAirplaneModeOn() { return Settings.System.getInt(getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0; } }
P.S: The isAirplaneModeOn() function is using depreceated method (pre API 17) just for the purpose of simple example and backward compatibility.
Now… lets say you want to create some other class, and move the function to that class:
import android.provider.Settings; public class MyOtherClass { ... public boolean isAirplaneModeOn() { return Settings.System.getInt(<span style="text-decoration: underline;">getContentResolver</span>(), Settings.System.AIRPLANE_MODE_ON, 0) != 0; } }
HEY?!!? Why Eclipse telling me: The method getContentResolver() is undefined for the type MyOtherClass
????? ….. Because getContentResolver() is a context method – Soon you realize you must have access to Context.. so What the solution?
Some solutions
I’ve read a lot about context(s). Maybe, most of the valuable stuff out there in the internet…
Some are saying to pass the context to the class and save a reference to that context like:
class YourNonContextClass { private Context context; public YourNonContextClass(Context context){ this.context=context; } public boolean isAirplaneModeOn() { return Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0; } }
Some are saying to pass the context to your static function like:
public class MyOtherClass { public static boolean isAirplaneModeOn(Context context) { return Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0; } }
Both solutions works. Both have their Pros and Cons. both require you to alter the code inside the function.
Solution – The Secret of ContextWrapper
Finally … After a fashion… With lot of experimentation, I’ve found a great solution that I really like! :
So What is ContextWrapper?
Proxying implementation of Context that simply delegates all of its calls to another Context. Can be subclassed to modify behavior without changing the original Context.
In other simple words: It’s a class that inherits another Context.
So, How to use the ContextWrapper?
Let’s talk about the function we discussed above and create a ContextWrapper class for it:
public class MyContextWrapper extends ContextWrapper { public MyContextWrapper(Context base) { super(base); } public boolean isAirplaneModeOn() { return Settings.System.getInt(getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0; } }
Note that nothing need to be changed in the isAirplaneModeOn() function as the class itself inherits the wrapper you’ve called from (Activity, Service, IntentService, etc).
To call the function just use:
boolean isAir = (new MyContextWrapper(this)).isAirplaneModeOn();
Where ‘this’ could be any context you’d like to. applicationContext, Service or Activity.
That’s it. Easy haa!
And choose what fits you best…
Development Specialist, Artist and Activist
Personal Website
Wouldn’t the last solution basically be the same as :
boolean isAir = (new YourNonContextClass(this)).isAirplaneModeOn();
What are the exact advantages of using a class inherited from ContextWrapper instead of the above?
Yes. it’s exactly the same.
But inside the class you would write:
2
3
super(base);
}
Instead of:
2
3
4
public YourNonContextClass(Context context){
this.context=context;
}
And calling the context method is shorter (like in activity):
Instead of:
So, if you move a method from your Activity into ContextWrapper class you don’t need to change a thing (add context. everywhere).
I think, there should be some other benefit because of using this ContextWrapper. Have to explore it a bit deeper
I am sure there is. reading from documentation : Proxying implementation of Context that simply delegates all of its calls to another Context. Can be subclassed to modify behavior without changing the original Context.
I don’t really know what the mean of “Proxying” and “delegates” and how it’s work. maybe looking in the code will brighten things up.
The real question is if ContextWrapper help us avoid memory leaks.
Hello, @Etay I think ContextWrapper can not help to avoid memory leaks. Check the ContextWrapper source. it holds a strong reference to context and not releases it.
@About Etay Cohen-Solal hey thanks. You saved my day. I was literally scratching my head since two hours. Bloody Context. Yours solution is super super simple easy than other solutions. Finally i can use Context in non-activity classes and I can divide the code into separate files for easy code management.
Hi,
Using this way i try to sendbroadcast but getting nullpointerException. Here is a code:
public class ConfigurationManager extends ContextWrapper {
public ConfigurationManager(Context base) {
super(base);
}
….
private void stopVoiceRecognizer() {
Log.d(“sender”, “Broadcasting voice Recognizer stop message”);
Intent intent = new Intent();
intent.setAction(“stop_voice_recognizer_service”);
(new ConfigurationManager(this)).sendBroadcast(intent);
}
Can you please suggest me where i am doing wrong.
You saved me buddy. Infact I had struggled with this too much. Big thanks.
Hello i am using a library function which need activity context but i am calling it using service context so . can proxy service context as activity context for that library fuction
thanks
Interesting approach of context wrapper in non activity class.Android Training
currently I’m using the first solution, passing the context or sometimes the Activity itself to the class, but the wrapper seems to be a better way.
Damn Simple & Clear explanation for “what is ContextWrapper” I was searching for… Thanks and Thumbs up to Etay Cohen-Solal 🙂
Hi , this solution seems to be great but as you have written
“To call the function just use:
boolean isAir = (new MyContextWrapper(this)).isAirplaneModeOn();
Where ‘this’ could be any context you’d like to. applicationContext, Service or Activity.”
Can’t this be used with fragments as my application is based of the fragment architecture . And making this i need to pass the context from the fragment itself.
How should i be doing it then?
Use getActivity() for context in fragment
And one more thing if in my fragment i use 5 common functions that i have now placed under the MyContextWrapper then for each function do i need to write like this only:
(new MyContextWrapper(this)).funcName();
or we can make something common for this???
This approach solves the memory leaks of dialog?
Example:
public class Endpoint extends ContextWrapper {
public Endpoint(Context base) {
super(base);
}
public void makeDialog() {
// getting context with getBaseContext()
ProgressDialog dialog = new ProgressDialog(getBaseContext());
dialog.setMessage(“Blá blá”);
dialog.show();
}
}
And in activity:
(new Endpoint(this)).makeDialog();
So, if I close my app with a dialog open, will throw a memory leak cause my activity is closed or the wrapper will support it?
Thx Alot 😀
You made my day.
Thank you
I liked your blog.Thanks for your interest in sharing your ideas.keep doing more.
Superb! Your blog is incredible. I am delighted with it. Thanks for sharing with me more information.
Great post you have to sharing. it is very useful and informative.
great post you shared with knowledgeable info, i would definitely use this method. Thanks for sharing the article.
Such a Great post shared, They are very helpful article. Your blog is incredible. Thanks for sharing your information.
nice post good work
Such a lovely post. Thank you for sharing with us.
Very Informative post.
Great information shared here its very useful and informative one
Excellent post.