I am not an expert in WeakReferences, as I am getting acquainted by them just now along the way.
I am using Timer with TimerTask in my activity.
It is known that Timers can not be reused whenever you have called cancel() on them, until you create a new instance of it.
So what I am doing is to create a Timer globally in my activity.
Timer timer;
and inside my onResume(), I instantiate it by timer = new Timer();
The reason for this is to avoid the Timer already cancelled exception. Because the onPause() might be called when the mobile gets screenlock or whatever, and I am calling timer.cancel() in my onPause() method.
My question is, when the timer was cancelled, does it automatically becomes prone for Garbage collection as it is totally pointless to use it again AFAIK. If this is the case, how fast does it get collected ?
Is using a WeakReference here comes in handy ? if not, where does it help to use it ?
Regardless of eligibility of Timer to be GC'ed you will not benefit from keeping a WeakReference to Timer instance, because, as you said, it can not be reused anymore after cancel().
WeakReference is useful to keep track of object that you can use, but do not want to keep that object in RAM if no one else uses it (i.e. no one keeps [hard] references to it). Then it will be GC'ed and your WeakReference also becomes useless. (and you do not prevent GC of the object by keeping only WeekReference to it).
Well, hope it is not too vague.
I personally use WeakReferences to have rough idea of possible memory leaks in junit tests.
I could give you another example of usage - instead of having custom inner Handler class defined in Activity class, which has implicit reference to your Activity and could create potential memory leaks, you could define custom Handler class as static nested class and keep WeakReference to your Activity instance as a private member, so you can continue calling your Activity methods from inside custom Handler class.
Related
I know you are using it quite well with your Non-UI codes in AsnycTask but I am just wondering if there is any kind of problem while using AsyntTask? I am not having any code which produce the problem. But I am just curious to know Any bad experience if you have with AsnycTask and would like to share it.
Memory Leak :
Even though activity is destroyed, AsyncTask holds the Activity's reference since it has to update UI with the callback methods.
cancelling AsyncTask :
cancelling AsyncTask using cancel() API will not make sure that task will stop immediately.
Data lose :
When screen orientation is done. Activity is destroyed and recreated, hence AsysncTask will hold invalid reference of activity and will trouble in updating UI.
Concurrent AsyncTasks: Open Asynctask.java go to line number 199, it shows you can create only 128 concurrent tasks
private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128);
Rotation: When Activity is restarted, your AsyncTask’s reference to the Activity is no longer valid, so onPostExecute() will have no effect.
Cancelling AsyncTasks: If you AsyncTask.cancel() it does not cancel your AsyncTask. It’s up to you to check whether the AsyncTask has been canceled or not.
Lifecycle: AsyncTask is not linked with Activity or Fragment, so you have to manage the cancellation of AsyncTask.
There are some workarounds to solve above issues for more details have a look at The Hidden Pitfalls of AsyncTask
I just want to share the information that if you are using Asynctask, it will keep on doing its work even of the activity does not exist.
So in case you have asynctask which starts in onCreate() of the activity, and you rotate the device. At each rotation, a new activity is created with a new instance of Asysntask. So many requests will be send over the network for same task.In this way, a lot of memory will be consumed which effects the app performance resulting in crashing it. So to deal with it Loaders(Asynctask Loaders) are used.
For more info check the video:
Loaders
I've got a view in a RecyclerView. And I call myView.post(runnable) in onBindViewHolder() method to gather information about myView after the layout pass finishes. Is there any risk of crashing my application if the host activity gets destroyed somehow before my runnable starts?
In general its safe. However if your onDestroy releases any resources or nulls out any variables that your Runnable depends on you could hit a corner case. For the most part I wouldn't worry about it though. It can't be called after finalize(), because the Runnable will keep a reference to your activity preventing it from being garbage collected until after the Runnable is run. That would be the real problem, but the framework/language prevent it.
From the Activity, I am creating a Handler to fire off my AsyncTask every 45 seconds in order to refresh the content of my ListView's DataAdapter. The AsyncTask works great and keeps the user informed on the progress through ProgressUpdates and Toast messages.
Since the thread's doInBackground is fire and forget and not re-usable, I am having to create a new instance of the AsyncTask from my Hander that is firing off every 45 seconds. The problem is when the screen is rotated and and then I get concurrent messages going off because the Hander was recreated and created a new instance of the AsyncTask, so the friendly user progress through ProgressUpdates and Toast messages is overwhelming and makes utilizing the ListView difficult.
And please don't suggest this as a solution: android:screenOrientation="portrait" is not an option.
For something that has to run so frequently, should I just be using a custom Thread and not the AsyncTask class? ToDo: Not shown, I have to update the Adapter later from the Sensor's onSensorChanged event to update bearings on for each location in the ListView, I was going to run that on a separate AsyncTask class because I don't need to notify the user everytime the device bearing has changed.
Since the AsyncThread cannot be reused, am I doing this all wrong? In short, what is the best way to have the Activity refresh the ListView and keeping off the UI thread when doing so?
The problem is when the screen is rotated and and then I get concurrent messages going off because the Hander was recreated and created a new instance of the AsyncTask.
Reason quoting from API Activity - Configuration Changes:
Unless you specify otherwise, a configuration change (such as a change in screen orientation, language, input devices, etc) will cause your current activity to be destroyed, going through the normal activity lifecycle process of onPause(), onStop(), and onDestroy() as appropriate.
So every object has a activity-scope life cycle (i.e. Handler, AsyncTask and etc. defined within your activity class) is suffered by this activity recreation. However, you can bypass this activity recreation, as stated in the later paragraph of Activity - Configuration Changes section:
In some special cases, you may want to bypass restarting of your activity based on one or more types of configuration changes. This is done with the android:configChanges attribute in its manifest. For any types of configuration changes you say that you handle there, you will receive a call to your current activity's onConfigurationChanged(Configuration) method instead of being restarted. If a configuration change involves any that you do not handle, however, the activity will still be restarted and onConfigurationChanged(Configuration) will not be called.
Not related to topic, but as a good practice, you should always destroy used object (Handler, AsyncTask and etc.) properly when activity is about to finish (i.e. in onDestroy() method).
For something that has to run so frequently, should I just be using a custom Thread and not the AsyncTask class?
AsyncTask is pretty handy but not suit for periodic task, I would use ScheduledExecutorService or TimerTask in this case, check out my answer here for sample code.
Can you please post a bit of your code ? It may be useful to understand where your problem is.
As york has pointed it out, you should probably use TimerTask. It seems that it suit better with what you are trying to do.
If it is the creation of a new instance of the Handler that create the probleme you can try something like this :
private Handler mHandler = null;
#Override
public void onCreate(Bundle _savedInstanceState) {
super.onCreate(_savedInstanceState);
setContentView(R.layout.my_layout);
if (mHandler == null) {
// TODO create your handler here
}
}
EDIT :
You can test _savedInstanceState == null too.
_savedInstanceState is used to save the state of the activity so turning the phone shouldn't be a problem anymore.
However, if you leave the activity and then go back to it, it will create a new handler (except if you instanciate it as a static variable).
Is it a good practice to use getApplicationContext() working with AsyncTask in order to do not have to attach and detach the Activity to avoid memory leaks when rotation changes occur and the Activity is destroyed? I thing it should be correct, as I actually need a Context that depends on the hole application, not the Activity itself.
And what is more, in those cases in which is better to use the Activity as context (because you need access to the Activity showing)... Instead of detaching it (assigning to null) when it is destroyed and then assign the new instance in onCreate(), could be just avoid detaching? So, just reasigning the new instance, this way, we could avoid problems of NullPointerException because there would always be a context to use!
This post and its answers are a good explanation of what to do. This post and its answers explain some good theory behind the AsyncTask and Context issue.
From my own experience I can say that in most cases it is better to use Activity as your Context, than getApplicationContext() when dealing with AsyncTask. This is because most of times you will need to access members from your Activity and you will only be allowed to do so if you have a reference to the Activity in your AsyncTask.
To answer my question about avoiding detach(), let me say that in this case you can avoid it or just do it without any problems, as #CommonsWare states in his answer. So, from what he says we are sure that we will not get a NullPointerException while the Activity is null during a rotation change:
onProgressUpdate() and onPostExecute() are suspended between the start of onRetainNonConfigurationInstance() and the end of the subsequent onCreate()
If I am not wrong, the main difference between not detaching explicitly and just re-attaching the new one in the onCreate() of the newly created Activity is that you free the old Activity instance some milliseconds later when just reattaching. But the final behavior is the same in both cases!
Hope this helps someone else! :)
Is it a good practice to null references to Activity Context, when my Activity finishes? I have 3 AsyncTask's, each of them can be running in several instances simultaneously. The update the UI in onPostExecute(). Nulling all Activity Context references in onDestroy() would be quite difficult and make the code messy. What is the best thing to do?
Check WeakAsyncTask for an example from Google of an asynctask that doesn't keep references alive beyond the activity lifecycle, and BetterAsyncTask from DroidFu for an example of a way to wire AsyncTasks so they can reconnect to new activity instances (after a rotation, for example); usage example is here.
There's probably not too much harm in keeping the references to Activity around for a short operation (e.g. a single small web request or small file write), but if there's the possibility for the tasks to pile up, it could cause a problem. For example, if your app reads a 200KB XML file from a server on creation, which let's say can takes 1 minute or more over EDGE, a quick flip of the phone open/closed 3 or 4 times could lead to 4 retained Activity instances -- you can run out of memory pretty quickly in this situation, not to mention the duplicated work.
For any really long-running processes, though, you should definitely consider an IntentService instead of an AsyncTask. They're designed for longer-running processes that aren't really tied to a specific activity - like how you can send an MMS and leave the activity to go do other things, and you get a nice happy toast informing you of the completion of the task whenever it finishes.
Do not keep long-lived references to a context-activity (a reference to an activity should have the same life cycle as the activity itself). Try using the context-application instead of a context-activity. Nulling the references is not needed when you do not need the opposite because of the memory troubles.
If the tasks will be eligible for garbage collection themselves shortly after your Activity finishes, I see no problem in keeping the references around.
If the tasks do outlive the activity for a significant amount of time, you should set all references to the Activity Context to null. See also the article Avoiding Memory Leaks.
Either way, it is good practice to use the Application Context (getApplicationContext()) instead of the Activity Context whenever you can. In this case you can't do this, because you need to post UI messages; I'm just mentioning it for completeness.
You can hold context reference using Weak reference. http://developer.android.com/reference/java/lang/ref/WeakReference.html
Weak referenced objects can be GC'd. You should just do check if you context reference is still valid every time you use it.