Handlers [Memory Leaks]

This post is part continuation of Memory Leaks in Android

Handler is also one of the choice, when we want to commnicate between any thread and Android’s main UI Thread. It is not so hard to use, little complex one when compared to AsyncTask, but offers more flexibilty as well. Below is excerpt from developer.android.com

A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue. Each Handler instance is associated with a single thread and that thread’s message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it — from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.

Lets takes similar example which we discussed in AsyncTask [Memory leaks], Similar implementation using Thread and Handler can be done as below

private void updateProgressUsingThread() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            for (int i = 0; i < AppConstants.LOOP_COUNT; i++) {
                    try {
                        Thread.sleep(AppConstants.THREAD_SLEEP_TIME);
                        progressCount++;
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    publishProgress(progressCount);
                }
        }
    }).start();
}

Problem:

You can see in below gif, how this perfectly looking code snippet is causing memory leak, Which is getting detected via awesome LeakCanary lib.

LeakyHandler

 

Now it not so hard to guess what happened, as we have similar issue with AsyncTask implementation,as we pressed back button, activity gets destroyed. But background Thread continues to run and it holds reference to our activity.

Solution:

Now we are going to miss AsyncTask cancel() method, unfortunately we don’t have any such method of Thread class. 😦

No need to worry, we developers are very good at borrowing GOOD things from various places 🙂 We can have our own flag to tell whether background thread was canceled or not, and use that to mimic AsyncTask solution here. Here is updated code snippet

private boolean isCanceled = false;

private void updateProgressUsingThread() {
    mThread=new Thread(new Runnable() {
        @Override
        public void run() {
                for (int i = 0; i < AppConstants.LOOP_COUNT; i++) {
                    if(!isCanceled) {
                        try {
                        Thread.sleep(AppConstants.THREAD_SLEEP_TIME);
                        progressCount++;
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    publishProgress(progressCount);
                }
            }
        }
    });
    mThread.start();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    isCanceled=true;
    mHander.removeCallbacksAndMessages(null);
}

And here is GIF with solution applied:)

Handler

 

So here LeakCanary didn’t detected any memory leak again, Awesome:) isn’t it ?

Leave a comment