在android開發中,使用Handler處理各種消息機制。
Handler用於處理和從隊列MessageQueue中得到Message。一般我們要重寫Handler的handleMessage(Message msg){}方法來處理,如下代碼:
使用內部類的方式實現,官方是不建議這樣寫的。
public class MainActivity extends Activity {
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
//處理各種接受消息邏輯
break;
default:
break;
}
};
};
}
這個時候Handler會被Android SDK中Lint工具檢查警告你(左邊那個黃色燈泡+嘆號):This Handler class should be static or leaks might occur 。
為什么靜態內部類可以解決這個問題呢?或者說靜態內部類和非靜態內部類的區別是什么?
舉例:class A{
int a;
static int b
class B{}
static class C{}
}
(A是外部類,B非靜態內部類,C靜態內部類,a普通字段,b靜態字段)
1)B非靜態內部類:
可以訪問A.a和A.b,也就是外部的屬性都能方位。因為B隱式的持有A類對象的引用,相當於A的屬性
2)C靜態內部類:
C只可以訪問A.b,不可以方位A.a。為什么?因為C不含有A的引用,它和A類是同一個級別,只不過寫到了A類的內部。
link的警告原因:
Handler匿名內部類,隱式的持有了外部類Activity的引用。
Message message = normalHandler.obtainMessage();
normalHandler.sendMessageAtTime(message , 100*1000);
得到的message中又含有這個Handler的引用(可以看源碼)。
在100秒后message被執行,這期間message被放在MessageQueue中,MessageQueue在Looper中,Looper是線程的本地變量。
也就是說MainActivity即使生命周期走完了也不會垃圾回收,為什么?因為Java的垃圾回收機制,就是看一個對象有沒有被引用(從線程中的主要對象開始,對象之間的引用形成網狀結構,如果有類的對象不在這張網上,就證明它沒被引用。這就是數據結構中圖的遍歷,什么連通子圖,非連通子圖)。而本文中一個MainActivity被Handler持有引用,Handler被Message持有引用,Message被MessageQueue持有引用,MessageQueue被Looper持有引用,Looper為線程本地變量,線程不被摧毀,它就不會被銷毀。
所以即便用戶已經切換、退出到別的Activity,MainActivity占有的內存仍舊不會被釋放。
解決方案:
打破引用鏈?
1.Message在100秒后被處理,之后回收Message,然后回收MainActivity。(所以是實際上,你只要不發很長時間的Message也不會有什么問題)
2.使Handler不持有MainActivity的引用,用弱引用WeakReference:(簡單講,就是只有WeakReference引用的對象,垃圾回收將回收該對象)
MyHandler handler = new MyHandler(this);
public static class MyHandler extends Handler {
private WeakReference<MainActivity> reference;
public MyHandler(MainActivity activity) {
reference = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
//處理接受消息邏輯
break;
default:
break;
}
}
}
為何Android界面更新,Handler作為匿名內部類來實現handlerMessage方法
最重要的不是線程安全問題,而是android組件的監聽方法中只能訪問final 的屬性,所以是無法修改的,只能把它交給handler處理。不能在非UI線程,繪制渲染潔面。
為何需要Handler而不用Thread。除了消息模型是UI框架的經典模式外,還涉及到UI組件不允許跨線程訪問的限制。無論是.NET也好,swing也好,android也好,不允許在非UI線程中操作這一點都一樣。
Handler便是android框架中異步線程代碼到達同步線程的官方通道。從另一個角度說,這種基於消息模型的通信模式有時也很有用。相關的例子有IntentService,HandlerThread等。
轉自:http://www.bkjia.com/Androidjc/904357.html
