Handlers and memory leaks in Android - android

Please have a look at the code below:
public class MyGridFragment extends Fragment{
Handler myhandler = new Handler() {
#Override
public void handleMessage(Message message) {
switch (message.what) {
case 2:
ArrayList<HashMap<String,String>> theurls = (ArrayList<HashMap<String,String>>) message.obj;
urls.addAll(theurls);
theimageAdapter.notifyDataSetChanged();
dismissBusyDialog();
break;
}
}
}
}
When I use handler like this I get a warning "handler should be static, else it is prone to memory leaks." Can someone tell me what is the best way to do this?

I recently updated something similar in my own code. I just made the anonymous Handler class a protected inner class and the Lint warning went away. See if something like the below code will work for you:
public class MyGridFragment extends Fragment{
static class MyInnerHandler extends Handler{
WeakReference<MyGridFragment> mFrag;
MyInnerHandler(MyGridFragment aFragment) {
mFrag = new WeakReference<MyGridFragment>(aFragment);
}
#Override
public void handleMessage(Message message) {
MyGridFragment theFrag = mFrag.get();
switch (message.what) {
case 2:
ArrayList<HashMap<String,String>> theurls = (ArrayList<HashMap<String,String>>) message.obj;
theFrag.urls.addAll(theurls);
theFrag.theimageAdapter.notifyDataSetChanged();
theFrag.dismissBusyDialog();
break;
}//end switch
}
}
MyInnerHandler myHandler = new MyInnerHandler(this);
}
You may have to change where I put "theFrag." as I could only guess as to what those referenced.

Here's a somewhat useful little class I made that you can use. Sadly it's still quite verbose because you can't have anonymous static inner classes.
import java.lang.ref.WeakReference;
import android.os.Handler;
import android.os.Message;
/** A handler which keeps a weak reference to a fragment. According to
* Android's lint, references to Handlers can be kept around for a long
* time - longer than Fragments for example. So we should use handlers
* that don't have strong references to the things they are handling for.
*
* You can use this class to more or less forget about that requirement.
* Unfortunately you can have anonymous static inner classes, so it is a
* little more verbose.
*
* Example use:
*
* private static class MsgHandler extends WeakReferenceHandler<MyFragment>
* {
* public MsgHandler(MyFragment fragment) { super(fragment); }
*
* #Override
* public void handleMessage(MyFragment fragment, Message msg)
* {
* fragment.doStuff(msg.arg1);
* }
* }
*
* // ...
* MsgHandler handler = new MsgHandler(this);
*/
public abstract class WeakReferenceHandler<T> extends Handler
{
private WeakReference<T> mReference;
public WeakReferenceHandler(T reference)
{
mReference = new WeakReference<T>(reference);
}
#Override
public void handleMessage(Message msg)
{
if (mReference.get() == null)
return;
handleMessage(mReference.get(), msg);
}
protected abstract void handleMessage(T reference, Message msg);
}

Per the ADT 20 Changes, it looks like you should make it static.
New Lint Checks:
Check to make sure that Fragment classes are instantiatable. If you accidentally make a
fragment innerclass non-static, or forget to have a default constructor, you can hit runtime
errors when the system attempts to reinstantiate your fragment after a configuration change.
Look for handler leaks: This check makes sure that a handler inner class does not hold an
implicit reference to its outer class.

If you read docs about AccountManager or PendingIntent, you will see that some methods take Handler as one of arguments.
For example:
onFinished - The object to call back on when the send has completed, or null for no callback.
handler - Handler identifying the thread on which the callback should happen. If null, the callback will happen from the thread pool of the process.
Imagine the situation. Some Activity calls PendingIntent.send(...) and put the non-static inner subclass of Handler. And then activity is destroyed. But inner class lives.
Inner class still holds a link to destroyed activity, it cannot be garbage-collected.
If you're not planning to send your handler to such methods, you have nothing to worry about.

I run into the same issue and I find that it is one of this topics with many questions and few answeres. My solution is simple and I hope it can help someone:
/* BEFORE */
private Handler mHandler= new Handler() {
#Override public void handleMessage(Message msg) {
this.doSomething();
};
};
We can create a static Handler subclass that simply runs a Runnable. The actual handler instance will know what to do through the runnable that will have access to instance variables.
/* AFTER */
static class RunnableHandler extends Handler {
private Runnable mRunnable;
public RunnableHandler(Runnable runnable) {
mRunnable = runnable;
}
#Override public void handleMessage(Message msg) {
mRunnable.run();
};
}
private RunnableHandler mHandler = new RunnableHandler(new Runnable() {
#Override public void run() {
this.doSomething();
} });
The warning is gone while the funcionality is the same.

A simple solution for this case might be:
Handler handler=new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message message) {
//do your stuff here
return false;
} });

Related

Can this code avoid the Android handler memory leak?

handler1 is a leak.
I want to convert handler1 code to handler2 code. Is that OK?
What is the difference between the two codes?
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// leaks!
Handler handler1 = new Handler()
{
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("LOG", "Hello~1");
}
};
Handler handler2 = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
Log.e("LOG", "Hello~2");
return false;
}
});
handler1.postDelayed(new Runnable() {
#Override
public void run() { }
}, 60000);
handler2.postDelayed(new Runnable() {
#Override
public void run() { }
}, 60000);
finish();
}
}
Why Leak Warning for handler1?
For the reason on leak warning, this article explains very well.
Quoting from the article
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.
So when you created handler1 by anonymous class, it will holds a reference to the MainActivity instance and MainActiviy can not be garbage collected.
Solution
Quoting from the article again
To fix the problem, subclass the Handler in a new file or use a static inner class instead. Static inner classes do not hold an implicit reference to their outer class, so the activity will not be leaked. If you need to invoke the outer activity’s methods from within the Handler, have the Handler hold a WeakReference to the activity so you don’t accidentally leak a context. To fix the memory leak that occurs when we instantiate the anonymous Runnable class, we make the variable a static field of the class (since static instances of anonymous classes do not hold an implicit reference to their outer class):
Following the article, update your code as follows:
public class MainActivity extends AppCompatActivity {
private static class MyHandler extends Handler {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("LOG", "Hello~1");
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Handler handler1 = new MyHandler();
handler1.postDelayed(new Runnable() {
#Override
public void run() { }
}, 60000);
finish();
}
}
Can handler2 solve the problem?
The answer from #Michael This Handler class should be static or leaks might occur: IncomingHandler
provides the solution.
Quoting from #Michael answer
As I understand it, this will not avoid the potential memory leak. Message objects hold a reference to the mIncomingHandler object which holds a reference the Handler.Callback object which holds a reference to the Service object. As long as there are messages in the Looper message queue, the Service will not be GC. However, it won't be a serious issue unless you have long delay messages in the message queue.
In your case, handler2 will hold a reference to Handler.Callback object.And since Handler.Callback is created by anonymous class, hence it will hold a reference to MainActiviy instance too. So MainActiviy instance can not be garbage collected also.
I try this code on emulator(android 28) and dump the memory, the profiler shows nothing to leak, I also try Leakcanary and shows same result. This makes me doubt the accuracy of the articles on the web. Then I noticed the difference,if I use Kotlin write this logic, the memory will not leak, but use the Java code will leak.
Later I found something interesting. In java, whether use outer class method or not,the anonymous inner class will hold outer object reference by constructor. In kotlin,if inner logic is not use outer class method,the anonymous inner class dose not hold the outer object reference.
I used Handler in Kotlin code that catches the incoming Bluetooth incoming message. This code has no lint leaks warnings:
private val incomingMsgHandler: Handler = Handler { msg ->
msg.obj?.let {
if (it is ByteArray) {
val msgStr = String(it)
setIncomingMessage(msgStr)
}
}
true
}
In short description, this uses Handler constructor with lambda callback.

This Handler class should be static or leaks may occur (null)

This Handler class should be static or leaks may occur (null)
Is the 'class' this message referring to 'MyActivity' here, since Handler is an object and i did declare it static. Should I ignore it or there something I should add, like 'static' somewhere in the 'MyActivity' declaration (I tried this and got errors). I notice 'WeakReference' is often suggested for this lint warning.
public class MyActivity extends Activity{
...
static Handler handler;
...
handler = new Handler()
{
public void handleMessage(Message msg) {
since Handler is an object and i did declare it static
You declared the data member to be static. However, you are using anonymous inner class, and therefore your subclass of Handler is not static.
Instead of:
handler = new Handler() {
public void handleMessage(Message msg) {
// do cool stuff
}
};
use:
handler=new MyVeryOwnHandler();
where MyVeryOwnHandler is either a regular Java class or a static inner class:
private static class MyVeryOwnHandler extends Handler {
public void handleMessage(Message msg) {
// do cool stuff
}
};
Note that the error is that the class needs to be static; it does not say that the object needs to be static.
To avoid leaks I also migrated to a static nested class. The explanation from Android Studio says this, it might help:
Since this Handler is declared as an inner class, it may prevent the
outer class from being garbage collected. If the Handler is using a
Looper or MessageQueue for a thread other than the main thread, then
there is no issue. If the Handler is using the Looper or MessageQueue
of the main thread, you need to fix your Handler declaration, as
follows: Declare the Handler as a static class; In the outer class,
instantiate a WeakReference to the outer class and pass this object to
your Handler when you instantiate the Handler; Make all references to
members of the outer class using the WeakReference object.
Before migration I used the implementation of a Looper thread as suggested by developer.android.com , which in the end lead to the warning. *scratch
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}

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.

Will this code from Android SDK sample cause a memory leak of the parent Activity?

So from reading/research about memory leaks it suggests to make all inner classes static to avoid memory leaks. However, by looking at the SDK samples (specifically TicTacToeLib) they implement their callbacks without the use of static inner classes. Will this cause a memory leak? If not, why?
private Handler mHandler = new Handler(new MyHandlerCallback());
private class MyHandlerCallback implements Callback {
public boolean handleMessage(Message msg) {
if (msg.what == MSG_COMPUTER_TURN) {
// Pick a non-used cell at random. That's about all the AI you need for this game.
State[] data = mGameView.getData();
int used = 0;
while (used != 0x1F) {
int index = mRnd.nextInt(9);
if (((used >> index) & 1) == 0) {
used |= 1 << index;
if (data[index] == State.EMPTY) {
mGameView.setCell(index, mGameView.getCurrentPlayer());
break;
}
}
}
finishTurn();
return true;
}
return false;
}
}
Yes, this sample will cause a leak in case it keeps a Message in the queue. But it's not a very severe leak since it is usually limited to a rather short amount of time.
But there is a rather simple way to prevent the leak:
Put the following two classes into your project
/** Callback that decouples the wrapped Callback via WeakReference */
public class SafeCallback implements Handler.Callback {
private final WeakReference<Handler.Callback> mCallback;
public SafeCallback(Handler.Callback callback) {
mCallback = new WeakReference<Handler.Callback>(callback);
}
#Override
public boolean handleMessage(Message msg) {
Handler.Callback callback = mCallback.get();
if (callback != null)
return callback.handleMessage(msg);
// else warn, return true, ..?
return false;
}
}
/** replacement for anonymous inner Handler implementations */
public abstract class SafeHandler implements Handler.Callback {
#Override
public abstract boolean handleMessage(Message msg);
public final Handler get() {
return new Handler(new SafeCallback(this));
}
public final Handler get(Looper looper) {
return new Handler(looper, new SafeCallback(this));
}
}
And now you can use Handler / Callback almost as you used to do but it's no longer leaking.
So either like
public class TestActivity extends Activity {
private Handler mHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new SafeHandler() { // << instead of new Handler() {
#Override
public boolean handleMessage(Message msg) {
// handle message
return false;
}
}.get(); // << Notice this added .get()
}
}
or like
public class TestActivity2 extends Activity implements Handler.Callback {
private Handler mHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler(new SafeCallback(this)); // << wrapped in SafeCallback
}
#Override
public boolean handleMessage(Message msg) {
// handle message
return false;
}
}
The leak problem with Handler is that each Message / Runnable (which is actually wrapped in a Message) knows it's target, i.e. has a hard reference to the Handler or Callback. And if that target is a non-static inner class, it will have an implicit hard reference to the outer class which is typically an Activity.
That means that as long as there are Messages enqueued for your Handler, your whole Activity can't be garbage collected.
To solve this issue that chain of hard references from Message to Activity has to be broken. The SafeCallback class does exactly that by keeping just a WeakReference towards your Activity.
That means, the Message has now a hard reference to SafeCallback but the part bind there can now be garbage collected. In case that happens Handler.Callback callback = mCallback.get(); will turn out null and the Message is simply discarded. There is no more useful target anyways. It is still leaking the SafeCallback itself but that's a pretty much empty class so it won't lead to problems.
I would approach it from the standpoint of what use case are you trying to solve, and not what the language itself is doing. If you "nested class" (not inner class because inner classes can't be static) needs to be able to call non-static methods on its parent class, or read non-static members, then you don't have much choice but to make it non-static. If you can get away with not accessing any of the parent class's non-static resources, then by all means do so (you'll save some memory that way anyways). However, if you're worried about memory leaks and you're going to make the nested class private as in your example, then you really shouldn't have anything to worry about because instances of that class can only be created locally to the parent class (unless you create a static member of the parent class that holds a reference to an instance of the nested class, in which case that object would be around until the parent class gets unloaded by the VM).
In summary, I wouldn't personally worry too much about whether or not your nested class is declared as static or non-static, but focus more on the lifecycle of instances of that class, if you're worried about leaking memory.

What is recommended way to update android ui from a -continuous- background thread?

I've read well enough on the subject to get well and thoroughly confused. I'm doing a workout tracker app such as RunKeeper, which tracks how long and how far the user has been say, running. I'm in the process of programming the main interface of this "workout" which shows a stopwatch-like layout which includes both a timer showing the time which is updated every second, and a counter showing how far he's run so far.
My problem is updating the interface. I have a stopwatch class keeping track of the time, and I calculate the distance based on gps locations, but I'm at a loss to find the recommended way to run a continuous thread in the background that updates the ui on a fixed time rate.
As far as I've been able to tell, I should either be implementing the Handler.Callback interface in the activity class, or have a separate Callback object together with a Thread, but I'm sort of at a loss on how to get it all to work together. I both need to update the time shown that I get from my stopwatch class (simple start/stop time calculation, nothing thread-related), and the distance calculated based on the locations received in onLocationChanged().
Here's a stripped down version of my Activity code:
public class WorkoutActivity extends Activity implements OnClickListener, LocationListener
{
private LocationManager locManager;
private boolean workoutStarted = false;
// The TextViews to update
private TextView timeLabel;
private TextView distanceLabel;
private Stopwatch stopwatch;
#Override
public void onCreate(Bundle savedInstanceState)
{
/*
... Interface initialisation
*/
stopwatch = new Stopwatch();
}
private void startWorkout() {/* ...*/}
private void stopWorkout() {/* ...*/}
private void pauseWorkout() {/* ...*/}
private void resumeWorkout(){/* ...*/}
public void onClick(View v) {/* ...*/}
public void onLocationChanged(Location location){/* ...*/}
}
According to most answers I've read around here I should use a Handler object extending the handleMessage method, but nowadays (at least according to the warning in Lint) you have to make such objects static to avoid memory leaks. That however, makes it a bit strange to directly access and change the other private objects in the activity class from within the Handler. I suppose you could solve this by making the objects you need to affect parameters in a class extending Handler, but I dunno, it feels like a bit of a "hack" (nested class within WorkoutActivity):
static class TimeHandler extends Handler
{
static final int MSG_START_TIMER = 1;
static final int MSG_UPDATE_TIMER = 2;
static final int MSG_STOP_TIMER = 3;
private static final int REFRESH_RATE = 1000;
private Stopwatch stopwatch;
private TextView timeLabel;
public TimeHandler(Stopwatch stopwatch, TextView label)
{
this.stopwatch = stopwatch;
this.timeLabel = label;
}
#Override
public void handleMessage(Message msg)
{
super.handleMessage(msg);
switch(msg.what)
{
case MSG_START_TIMER:
stopwatch.start();
this.sendEmptyMessage(MSG_UPDATE_TIMER);
break;
case MSG_UPDATE_TIMER:
timeLabel.setText(stopwatch.getElapsedTimeString());
this.sendEmptyMessageDelayed(MSG_UPDATE_TIMER, REFRESH_RATE);
break;
case MSG_STOP_TIMER:
this.removeMessages(MSG_UPDATE_TIMER);
stopwatch.stop();
timeLabel.setText(stopwatch.getElapsedTimeString());
break;
}
}
So, could anyone please explain the "standard" way of updating the UI from a continuous background thread? Oh, and sorry for the long question, just wanted to be thorough.
Use runOnUiThread().
Define a Runnable:
private Runnable mRunnable = new Runnable() {
#Override
public void run() {
mTextViewOne.setText("10 miles!");
mTextViewTwo.setText("40 minutes!");
}
};
Inside your continuous thread:
runOnUiThread(mRunnable);
USe the following thread in AsyncTask... I hope this will work for you ....
Handler mHandler;
private final Runnable mRunnable = new Runnable() {
public void run() {
Call your AsyncTask Class;;;;
mHandler.postDelayed(mRunnable, 1000);
}
};

Categories

Resources