调用完 Handler#removeCallbacks() 就安全了吗?
Handler
容易引起内存泄露,这是大家都知道的,所以你应该会在适当的时候调用 removeCallbacks()
方法来移除消息。但当以下使用场景时,依然可能会出现内存泄露。
1 | // ... |
mTimerRunnable
是一个在非主线程中运行的循环操作,一旦启动了它,就会每隔 DELAY_INTERVAL
时间被执行一次,所以在 Activity 退出时,应该停止它,否则就会出现内存泄露。停止它的方式就是调用 removeCallbacks()
把它从mDaemonHandler
的消息队列中移除。但这一操作如果处在 mDaemonHandler
线程正在执行 longTimeOperation()
时,mTimerRunnable
之后还是会被添加到 mDaemonHandler
线程的消息队列中。
要保证消息能够移除掉,可以这样写:1
2
3
4
5
6 mDaemonHandler.post(new Runnable() {
public void run() {
mDaemonHandler.removeCallbacks(mTimerRunnable);
}
});
这样就保证了移除 mTimerRunnable
的操作和 mDaemonHandler
在同一线程中,不会和 mTimerRunnable
『并发执行』。写成更通用的:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38import android.os.Handler;
import android.os.Looper;
/**
* @author linroid <linroid@gmail.com>
* @since 25/11/2016
*/
public class SafetyUtils {
public static void removeCallbacks(final Handler handler, final Runnable callback) {
if (handler.getLooper() == Looper.myLooper()) {
handler.removeCallbacks(callback);
} else {
handler.post(new Runnable() {
public void run() {
handler.removeCallbacks(callback);
}
});
}
}
public static void removeMessages(final Handler handler, final int what) {
removeMessages(handler, what, null);
}
public static void removeMessages(final Handler handler, final int what, final Object obj) {
if (handler.getLooper() == Looper.myLooper()) {
handler.removeMessages(what, obj);
} else {
handler.post(new Runnable() {
public void run() {
handler.removeMessages(what, obj);
}
});
}
}
}