When I use the Android Context within an AsyncTask#doInBackground, is it thread safe? The context is provided via constructor or via getApplicationContext() from a surrounding Activity. This simple questions is asked a lot at stackoverflow and else where but I found not a clear answer?
E.g. in the doInBackground() I use the context in order to Instantiate an DAO class.
#Override
protected Void doInBackground(Void... params) {
ExampleDao dao = new ExampleDao(context);
...
}
I saw several examples doing that in this way, but I cannot image that this is thread-safe, because the context is now accessed by the main tread (UI Thread) and the worker thread.
You can always access the context from different Thread as long as you are not changing something and you only retrieve resources through the context I don't see a problem with Thread-safety.
The problem is that the context will stay in memory and active as long as the Thread runs. This is a good thing for you because you can rely on having a valid context all the time.
The bad thing is that if you pass an Activity as a context all the views and member variables from this activity will also stay in memory and this can lead to a very late garbage collection for a lot of memory, like Waqas suggested.
On thing I would not do from a different Thread is accessing methods from Context subclasses like setTheme() that will affect the currently displayed views.
If you dont need to do anything with Views then always try to use getApplicationContext() which refers to application's context (not activity's context) and may help you to avoid memory leaks while threading or orientation-changes. So, i guess it fits for your needs in AsyncTask too.
Context is not threadsafe actually. But it is ok to pass an instance of application context to write to db for example.
Related
I have created a singleton class that performs some DB operation, every activity will call this class, and i need to pass context to it.
This is what each activity will do.
AnalyticsWrapper analyticsWrapper= AnalyticsWrapper.getInstance();
analyticsWrapper.reportView(MainActivity.this)
Now i am little confused about what can go wrong when i am passing activity reference to a singleton class.
I have few questions.
What is the good way of passing context to a long running task.
Is it better if i pass getApplicaitonContex() instead of
MainActivity.this here.
Will it increase memory, when each activity will be passing its context to singleton class, and it can lead to memory leak.
I don't think there is anything wrong using application context for DB Singleton, it will likely outlive Activity so passing Activity Context will leak. I've been passing App Context to Database instances for a long time and it never caused any issue with increasing memory or functionality.
Somewhere in the application, I need to get a localized string using the getString method for an error message. For this, I need a Context instance, gotten from for example an Activity. Is this really how this is designed? Am I really forced to pass around these objects into classes and methods or am I missing the point and is there some other way to get a string reference?
To clarify, in an Activity I have an inner AsyncTask subclass that in doInBackground instantiates a new class for some short network processing outside the UI thread. I want error messages to be localized and for that I need to pass in a Context instance (in other words, the Activity) into that class. The design of getting value resources from the XML files just seems to be a bit unintuitive. It makes me wonder why this is so coupled together with Context instances and not something static or - forgive me - a singleton, as Context implies to be the global application context and not just a part of it like an Activity.
No, you should not do this. A simple rule is; if what you need the context for is touching the UI or is only associated with the internals of the activity class, then you should use the activity context. Even then, it is important that any reference to the context does not have a lifetime which is greater than that of the activity.
The big danger of not following this is that you pass out a reference to the activity context to somewhere deeper in your code and your activity is destroyed whilst the reference you are holding is still in scope. You just leaked your activity and everything it has a reference to. I would recommend not passing the activity context outside the activity unless truly essential and even then, be very sure to control that life time.
So, it the context is needed for something which is not UI related, such as your need to get a string resource, then use the application context. Inside an activity, and where the string reference is declared in the activity, then using the activity context would be acceptable and in my opinion, preferred as you are making a conscious decision regarding scope and life time.
That said, you should ask whether this particular method is better placed in an activity. It may well not be but do ask yourself.
Finally, a small pedantic point. You do not pass objects anywhere. You pass a reference, in fact a value of a reference to the object. Everything in Java is passed by value.
You could always extend the application class. Make a static method on there for getInstace() to get the context.
I'm trying to create my own class for reading lines from a file, but that seems to be the problem.
From what I've been able to determine standard (Java) ways don't work under Android. I need to getResources() and so on.
public myInput(Context context) throws FileNotFoundException{
super();
br = new BufferedReader(new InputStreamReader(context.getResources().
openRawResource(R.raw.file)));
}
That's the constructor. I'm trying to create it like this.
public void choosePassword(Context context){
try{
myInput fromFile = new myInput(context);
} catch(Exception e){
}
}
The metod choosePassoword() is being called form my Activity class and to be honest don't know what he wants for Context. I want to give the method choosePassword() the file from which he should choose that password, that's what I want... can someone help me do just that?
An Activity is an indirect sub-class of Context so you can simply use choosePassword(this) when calling it from your Activity.
... to be honest don't know what he wants for Context
OK. This is an important thing to understand in Android. Contexts are the basis by which almost all apps interact or even have an identity. A Context essentially identifies where a Component's run instruction originated (this is an oversimplification). For an Android Component to run, it must have a Context to run in. Luckily, in most circumstances, the Context is provided for you. There are two specific types of Contexts that you will almost always have access to:
Every Activity is a Context. This one is subject to Lifecycle method calls.
Every Application is a Context. This one is outside of the Lifecycle and is initialized before any other Component of the Application is even created.
Both of these may be used whereever you may need a Context. If you need the Application Context, you may get it from nearly any component with the getApplication() method.
For Your Purposes
This makes your calls quite easy. If all of the calls are made from your Activity, then you may supply this as your argument. Even better, if the methods themselves are part of your Activity, you need not necessarily pass the Context as an argument and again, simply use this.
Of Important Note
You will learn that sometimes, it is easier to get one Context or another. You will also learn that sometimes while it may be more difficult, it is safer to use one Context over the other. For this, I would recommend reading up on the Lifecycle of an Activity. Not using the right one can result in memory leaks and unsafe execution. In general, if you need a Context for data or execution that only survives the Lifecycle, you can use an Activity. If you need a Context for data or execution that occurs outside the Lifecycle, use the Application.
Anyhow, didn't mean to write a book. There is a wealth of information on Contexts, how to use them and which to use. Certainly read up on it. It will make your life a ton easier.
Hope this helps,
FuzzicalLogic
In android, I need reference "context" or to say pass "context" to several classes. For this purpose I have implemented a static class which holds the "context" and all other class access context through it.
//let's say I have a static class DataHolder
//and my main acitivity i.e. whose context need to be refrenced
public class DataHolder{
public static Context context;
}
public class MainActivity extends Activity{
public void onCreate(Bundle bundle){
DataHolder.context = getApplicationContext();
}
}
So, is this process ok to be implemented or it is not the right way to reference in Android application.
The issue here is not about efficiency, but about the inherent risks of storing your context statically.
The context can change in many events, the most likely one is changing the device orientation, so you shouldn't relay on it always. I think you should pass the Context in the constructor to each class you think would use it (or, rather, redesign your code so you don't need it where it's not available, although this may be a bit tricky).
In the worst case scenario, you should try to update it as frequently as you can. But, then again, what's the point in having it always accessible? I think the risks are not worth the laziness (sorry if it sounds rude, I don't mean it to) of making a careful app design.
You should definetely avoid it, since it may lead to a memory leak.
Read: Avoiding memory leaks
This means that views have a reference to the entire activity and therefore to anything your activity is holding onto; usually the entire View hierarchy and all its resources. Therefore, if you leak the Context ("leak" meaning you keep a reference to it thus preventing the GC from collecting it), you leak a lot of memory. Leaking an entire activity can be really easy if you're not careful
If I interpret this article correctly, passing the activity context to AsyncTasks is a potential leak, as the activity might be destroyed while the task is still running.
How do you deal with this in AsyncTasks that are not inner clases and need access to resources or to update the UI?
Additionally, how can you avoid leaking the context if you need references to progress dialogs to dismiss them?
If I understand your question correctly: Java's WeakReference or SoftReference class is a good fit for this type of situation. It will allow you to pass the context to the AsyncTask without preventing the GC from freeing the context if necessary.
The GC is more eager when collecting WeakReferences than it is when collecting SoftReferences.
instead of:
FooTask myFooTask = new FooTask(myContext);
your code would look like:
WeakReference<MyContextClass> myWeakContext = new WeakReference<MyContextClass>(myContext);
FooTask myFooTask = new FooTask(myWeakContext);
and in the AsyncTask instead of:
myContext.someMethod();
your code would look like:
myWeakContext.get().someMethod();