Should I manually close HandlerThreads created by my application when destroying the activity?
Asked Answered
T

5

11

My app is composed of a single Activity. In this activity, I'm creating multiple HandlerThreads which run in a loop to do socket blocking operations.

Currently I post a quit message to everyone of these HandlerThreads during my Activity.onDestroy().

Sometimes, when I open my app, close it and relaunch it, it crashes (many time due to posting a message to a handler thread which is not running).

My question is: What is the right way to close HandlerThread when I close my app? (Note that those threads might be blocking on a socket operation).

EDIT: More information: I have a pool of Handler Threads which is initiated in onCreate (No problem when I'm launching my app at the first time).

Each handler runnable loop is wrapped with an

 if (shouldRun) {
//body
} 
else { 
 close();
}

statement.

the close method remove all pending messages and runnables and post a message to the handler that will cause him to call its looper.quit(). This way, if the current handler thread is blocked by IO operation, only once it will finish it he will quit().

Thrift answered 18/2, 2013 at 8:42 Comment(1)
Please analyze the cause of the crash. Maybe the true reason is that your HandlerThread objects try to post something to the Activity which dies not exist anymore. You need to inform your Threads which are still running that they lost their context.Boys
B
1
  • You must have some inconsistency there, otherwise your App wouldn't crash. Are you sure that a HandlerThread which is not running is really the reason? Don't you create HandlerThread objects when your Activity is created?
  • If your HandlerThreads are waiting on I/O operations, I would consider to try and interrupt them. Simply removing callbacks and messages and asking the Looper to quit, even sending temrination messages to the Handler, will do nothing. The HandlerThread object will still be around until Android kills the process (which may or may not occur). This means that "your app will collect zombie HandlerThread objects" which are probably unreachable. Unless, of course, you can send those HandlerThreads a termination message which arrives on the channel they block on.
  • It would be much better to re-use the HandlerThread objects. A Service might be the right model to do this.
  • Also, if Threads survive your Activity, you need to inform them that their communication peer (your Activity) is gone. Otherwise, they may refer to something which is already gone.
Boys answered 18/2, 2013 at 9:1 Comment(1)
Please post the exception with stack trace. Also, the core question is, do your HandlerThread objects maintain references into your Activity.Boys
P
3

Yes, it would be a good idea to close it. Also make sure to remove your callbacks.

@Override
public void onDestroy() {
    super.onDestroy();
    handler.removeCallbacksAndMessages(null);
    handler.getLooper().quit();
}
Pyrrha answered 18/2, 2013 at 8:46 Comment(3)
But then I get those crashes when relaunching my app.. Already tried the extended answer also..Thrift
Are you making a new Handler/Thread on restart and calling Looper.prepare()/Looper.loop() again?Pyrrha
As I understand it, @Daniel has HandlerThread objects which wait on blocking I/O operations. Asking the Looper to quit() will have no immediate effect.Boys
B
2
    /**
 * Ask the currently running looper to quit.  If the thread has not
 * been started or has finished (that is if {@link #getLooper} returns
 * null), then false is returned.  Otherwise the looper is asked to
 * quit and true is returned.
 */
public boolean quit() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quit();
        return true;
    }
    return false;
}

Above is the 'quit' method of the source code of HandlerThread.java, just invoke it directly.

Why should called quit? Below is 'run' method of the source code of HandlerThread.java.

    public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();//always loop except for a Message with null target

    mTid = -1;
}

The answer is 'loop is a 'while(true)' method,It will return until receive a Message with null target.

Bethel answered 2/2, 2015 at 16:11 Comment(0)
B
1
  • You must have some inconsistency there, otherwise your App wouldn't crash. Are you sure that a HandlerThread which is not running is really the reason? Don't you create HandlerThread objects when your Activity is created?
  • If your HandlerThreads are waiting on I/O operations, I would consider to try and interrupt them. Simply removing callbacks and messages and asking the Looper to quit, even sending temrination messages to the Handler, will do nothing. The HandlerThread object will still be around until Android kills the process (which may or may not occur). This means that "your app will collect zombie HandlerThread objects" which are probably unreachable. Unless, of course, you can send those HandlerThreads a termination message which arrives on the channel they block on.
  • It would be much better to re-use the HandlerThread objects. A Service might be the right model to do this.
  • Also, if Threads survive your Activity, you need to inform them that their communication peer (your Activity) is gone. Otherwise, they may refer to something which is already gone.
Boys answered 18/2, 2013 at 9:1 Comment(1)
Please post the exception with stack trace. Also, the core question is, do your HandlerThread objects maintain references into your Activity.Boys
C
0

The best practices approach would be to remove the callbacks to your handlers in your activities onDestroy(). See this answer for more:

https://mcmap.net/q/640297/-how-to-stop-the-handler

Cohlette answered 18/2, 2013 at 8:50 Comment(0)
B
0

The HandlerThread is stopped when the Looper is quitted. HandlerThread.getLooper().quit() when you stop your activity. (see http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1/android/app/IntentService.java#IntentService.ServiceHandler.%3Cinit%3E%28android.os.Looper%29 for a good example of a proper HandlerThread use)

Britt answered 18/2, 2013 at 9:1 Comment(2)
As I understand it, @Daniel has HandlerThread objects which wait on blocking I/O operations. Asking the Looper to quit() will have no immediate effect.Boys
possible, yes. In which case, handlerThread.interrupt() should stop those operations (but that's not specific to HandlerThread)Britt

© 2022 - 2024 — McMap. All rights reserved.