How/when is a Handler garbage collected? - android

Inside a class of mine I have the following code:
mHandler = createHandler();
private Handler createHandler() {
return new Handler() {
public void handleMessage (Message msg) {
update();
if (!paused) {
sendEmptyMessageDelayed(0, 300);
}
}
};
}
The documentation says:
http://developer.android.com/reference/android/os/Handler.html
Each Handler instance is associated with a single thread and that thread's message queue
So if I understood correctly the Handler is not garbage collected as long as the application thread is running, is that correct?
In my specific example since the Handler is an anonymous inner class it has an implicit reference to the enclosing Object and the whole hierarchy of objects that is pointed by it. This looks to me like a recipe for memory leaking.
Btw, I can make the Handler stop sending messages(that's why I have the if (!paused)) but this won't make it be GCed, right?
So is there a way to remove the Handler from the message queue and get it to be GCed?

An examination of the Handler source reveals more details.
Here is some debug code from the Handler() constructor that was added by Romain Guy:
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
The warning is clear: Don't declare your Handler subclass as an inner class.
The Handler's looper is obtained from a static ThreadLocal instance:
mLooper = Looper.myLooper();
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
Anatomy of the leak:
The main app thread retains the Looper and its MessageQueue, the Messages in the queue retain a link to their target Handler, and the Handler -- unless it is a static nested class with a WeakReference to your Activity -- will retain your Activity and its views.
You could instead try to plug this leak by cleaning up your messages:
handler.removeMessages(what);
but this is easier said than done.
Also see On Memory Leaks in Java and in Android

In my specific example since the Handler is an anonymous inner class it has an implicit reference to the enclosing Object and the whole hierarchy of objects that is pointed by it.
You could reduce the impact of the potential leak to almost nothing by using a static nested class instead of an anonymous inner class.

No, stop sending message doesn't make GC work. As the doc points out, it bounds to the thread which creating it. If thread is running, the handler won't be recycled by GC.
Why do you think this could cause memory leaking? What do you mean by "implicit reference to the enclosing Object"?

Related

Can adding anonymous runnables in the queue of a Handler thread cause a memory leak?

Will this code cause a memory leak if it is present in the Activity VS ViewModel component?
handlerThread = new HandlerThread("myHandlerThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do work
}
}, 1000);
#Override
protected void onDestroy() {
super.onDestroy();
handlerThread.quit();
}
Will replacing the anonymous runnable class with a static class that extends Runnable make any difference? This was mentioned #4:13 in this video tutorial!
Why would an anonymous runnable hold reference to an Activity or ViewModel?
In Java, non-static inner and anonymous classes hold an implicit reference to their outer class. Static inner classes, on the other hand, do not.
Avoid using non-static inner classes in an activity if instances of the inner class could outlive the activity’s lifecycle. Instead, prefer static inner classes and hold a weak reference to the activity inside.
Source 1
Source 2
As for doing the same in the ViewModel instead of an Activity, if a memory leak occurs it will have a lesser magnitude in case the ViewModel didn't hold a reference to memory-intensive objects that should be garbage collected. But still, a memory leak threat would be still possible.
This Link is also very informative
This playlist contains all about how to properly use Handlers/Threads/HandlerThreads

Using a Static Handler to update the UI thread

When using a background thread to do work, typically you'd update the UI through a Handler.
One way to do this was defining a handler at the class level as outlined in this answer, and this answer
final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
//update UI or call class methods here
}
};
However, this construct would result in the following warning
Handler class should be static otherwise memory leaks might occur
Another way to do this was to use a static inner class as outlined in this answer, and this answer
static class MyHandler extends Handler {
private final WeakReference<Type> myWeakReference;
MyHandler(Type reference) {
myWeakReference = new WeakReference<Type>(reference);
}
#Override
public void handleMessage(Message msg)
{
//Update UI or call class methods here using weak reference
}
}
However, this form of constructor has been Deprecated according to the Android docs.
public Handler ()
This constructor is deprecated. Implicitly choosing a Looper during
Handler construction can lead to bugs where operations are silently
lost (if the Handler is not expecting new tasks and quits), crashes
(if a handler is sometimes created on a thread without a Looper
active), or race conditions, where the thread a handler is associated
with is not what the author anticipated. Instead, use an Executor or
specify the Looper explicitly, using Looper#getMainLooper, {link
android.view.View#getHandler}, or similar. If the implicit thread
local behavior is required for compatibility, use new
Handler(Looper.myLooper()) to make it clear to readers.
How should updating the UI from a Handler be done currently, and should a Handler still be used for this purpose.
As you stated the docs, it says to use Looper.getMainLooper(), just change your code to:
MyHandler(Type reference) {
super(Looper.getMainLooper());
myWeakReference = new WeakReference<Type>(reference);
}
to update the UI from the main/UI thread.

Will handler inside a method leak memory?

I know handler declared in a class may leak memory since it holds a reference to its outer class. In this case, we should use static nested class with weak reference.
But What if a handler is declared inside a method. I faced below case and not sure is it a correct implementation. Could someone please explain or give me a hint? I even don't know what I should search for.
private void methodA(){
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
methodB();
}
}, 10*1000);
private void methodB(){
//textView holds a reference to a activity
textView.setText("hello");
}
It can under certain conditions. If the runnable passed is an anonymous or inner class, as in your example, it holds an implicit reference to 'this' and prevents 'this' from being garbage collected until the runnable is processed off the queue (so if your method never runs, like if your handler thread gets stopped without clearing the queue, it will leak).
In the case where you are worried about the conditions for a memory leak occurring or hanging onto objects too long, then you need to make your runnable a static class that has a weak reference initialized in the constructor, something like:
private static MyRunnable implements Runnable
{
private final WeakReference<MyClass> myClass_weakRef;
public MyRunnable(MyClass myClassInstance)
{
myClass_weakRef = new WeakReference(myClassInstance);
}
#Override
public void run()
{
MyClass myClass = myClass_weakRef.get();
if(myClass != null)
myClass.methodB();
}
}
private void MethodA()
{
Handler handler = new Handler();
handler.postDelayed(new MyRunnable(this), 10*1000);
}
Creating a Handler inside your method isn't a special case. It falls under the same circumstances, in that the Message you post will live in the message queue until it's processed.

What's the diference between the two ways of initializing Handler?

I am confuse about the following two ways to initialize the Handler. What's the difference ?
1. First way:
class MyFirstActivity extends Activity {
class Handler mHandler = new Handler();
...
}
2. Second way:
class MySecondActivity extends Activity {
private MyHandler mHandler;
#Oerride
protected void onCreate(Bundle bundle) {
mHandler = new MyHandler(getMainLooper());
}
private final class MyHandler extends Handler {
public MyHandler(Looper looper) {
super(looper, null, true);
}
...
}
}
Note:
I know there is the documentation:
Handler() - Default constructor associates this handler with the Looper for the current thread.
If this thread does not have a looper, this handler won't be able to receive messages so an exception is thrown.
and
Handler(Looper looper) - Use the provided Looper instead of the default one.
It means I want to know more, like
when quit, are there some special operations to do?
Which way is better (or More efficient)?
Thanks~
The Handler (Looper looper) constructor (second way) is used when creating Handler from threads, which do not have default looper, or when you want the handler to run actions on a different thread than your own.
In your "second way" example there is no need to use this type of constructor, the default one will do the same. And as the Activity constructor is invoked on the same thread as onCreate(..) method, two possible initializations ("first" and "second way") of Handler are totally equal.
UPD: make sure not to create inner Handler class.
As per documentation here
Handler() - Default constructor associates this handler with the
Looper for the current thread.
If this thread does not have a looper, this handler won't be able to receive messages so an exception is thrown.
and
Handler(Looper looper) - Use the provided Looper instead of the default one.
Here Looper is Class used to run a message loop for a thread. Check this
It's documented here. Basically second example explicitly tries to get app's main looper, while first one leaves this to the Handler's constructor:
Default constructor associates this handler with the Looper for the
current thread.
Since your both classes are Activities, there's no difference in this particular case.

Is it OK to use previous Handler in Activity created before onDestroy() onPause()?

Is it OK to reuse a Handler object in the next life of Activity which was previously created in its previous session (before onPause, onDestroy()) ?
Like I create a Handler in Activity propagate it to other objects elsewhere, the Activity dies or pauses, then comes to life again and use the old handler ?
// In the oncreate() method I have this code to recreate handler every time
// Then I set the handler to a static Global object
// Other Objects use the global object's static method to get
//fresh handler every timebefore calling sendMessage()
/**
* Set up handler
*/
Handler h = new Handler(new Callback()
{
public boolean handleMessage(Message msg)
{
handleServiceMessage(msg);
return true;
}
});
uiglobal = new UIGlobals(h);
UiGlobals is declared as
private static UIGlobals uiglobal = null;
Not sure if the above approach is correct ..
my GlobalUI class looks like this
public class UIGlobals
{
private static Handler handler = null;
public UIGlobals(Handler h)
{
handler = h;
}
public static Handler getHandler()
{
return handler;
}
}
If you have build your custom Handler class this should work but if you have defined your customized handler in your activity you have to unregister all handler messages in onPause. Otherwise you get a null pointer exception.
But i dont know in whick scenario you need this functionality... I normalley use Handler for UI access but for communication between activity and logic observer pattern.
If your handler is static and the Application (not the activity) hasn't been removed from memory, next time activity starts, static objects will be there.
If your handler is static and the Application has been removed from memory (i.e. service, threads, etc. are all stoped and you exit the only active activity) the next time you start activity, the Aplicationobject will be restarted and static objects will be recreated.
If your handler is not static, the you should be recreating it everytime you create activity, and of course, you will get a new one.
You need to post code or be more specific on your situation, if you want to have a more concrete answer.

Categories

Resources