java handler的用法_Handler和内部类的正确用法
PS:本文摘抄自《Android高級(jí)進(jìn)階》,僅供學(xué)習(xí)使用
Android代碼中涉及線程間通信的地方經(jīng)常會(huì)使用Handler,典型的代碼結(jié)構(gòu)如下。
1
2
3
4
5
6
7
8
9
public?class?HandlerActivityextends?Activity{
//可能引入內(nèi)存泄漏的用法
private?final?Handler mLeakyHandler =new?Handler(){
@Orrvide
public?void?handleMessage(Mesage msg){
//...
}
};
}
使用Android Lint分析這段代碼,會(huì)違反檢測(cè)項(xiàng)AndroidLintHandlerLeak,得到如下提示。
1
This Handlerclass?should bestatic?or leaks might occur.
那么產(chǎn)生內(nèi)存泄漏的原因可能是什么呢?我們知道,Handler是和Looper以及MessageQueue一起工作的,在Android中,一個(gè)應(yīng)用啟動(dòng)后,系統(tǒng)默認(rèn)會(huì)創(chuàng)建一個(gè)為主線程服務(wù)的Looper對(duì)象,該Looper對(duì)象用于處理主線程的所有Message對(duì)象,它的生命周期貫穿于整個(gè)應(yīng)用的生命周期。在主線程中使用的Handler都會(huì)默認(rèn)綁定到這個(gè)Looper對(duì)象。在主線程中創(chuàng)建Handler對(duì)象,它會(huì)立即關(guān)聯(lián)到主線程Looper對(duì)象的MessageQueue,這時(shí)發(fā)送到MessageQueue中的Message對(duì)象都會(huì)只有這個(gè)Handler對(duì)象的引用,這樣在Looper處理消息時(shí)常能回調(diào)到Handler的handlerMessage方法。因此,如果Message還沒(méi)有被處理完成,那么Handler對(duì)象也就不會(huì)被垃圾回收。
在上面的代碼中,將Handler的實(shí)例聲明為HandlerActivity類(lèi)的內(nèi)部類(lèi)。而在Java語(yǔ)言中,非靜態(tài)內(nèi)部匿名類(lèi)會(huì)持有外部類(lèi)的一個(gè)隱式的引用,這樣就可能會(huì)導(dǎo)致外部類(lèi)無(wú)法被垃圾回收。因此,最終由于MessageQueue中Message還沒(méi)處理完成,就會(huì)持有Handler對(duì)象的引用,而非靜態(tài)的Handler對(duì)象會(huì)持有外部類(lèi)HandlerActivity的引用,這個(gè)Activity無(wú)法被垃圾回收,從而導(dǎo)致內(nèi)存泄漏。
一個(gè)明顯的會(huì)引入內(nèi)存泄漏的例子如下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public?class?HandlerActivityextends?Activity{
//可能引入內(nèi)存泄漏的用法
private?final?Handler mLeakyHandler =new?Handler(){
@Orrivide
public?void?handleMessage(Mesage msg){
//...
}
};
@Orrivide
protected?void?onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//延遲5分鐘發(fā)送消息
mLeakyHandler.postDelayed(new?Runnable(){
@Orrivide
public?void?run(){/* ... */}
},1000*60*5);
}
}
由于消息延長(zhǎng)5分鐘,因此,當(dāng)用戶(hù)進(jìn)入這個(gè)Activity并退出后,在消息發(fā)送并處理完成之前,這個(gè)Activity是不會(huì)被系統(tǒng)回收的(系統(tǒng)內(nèi)存確實(shí)不夠使用的情況例外)。
如果解決呢。有兩個(gè)方案。
在子線程中使用Handler,這時(shí)需要開(kāi)發(fā)者自己創(chuàng)建一個(gè)Looper對(duì)象,這個(gè)Looper對(duì)象的生命周期同一般的Java對(duì)象,因此這種用法沒(méi)有問(wèn)題。
將Handler生命為靜態(tài)的內(nèi)部類(lèi),前面說(shuō)過(guò),靜態(tài)內(nèi)部類(lèi)不會(huì)持有外部類(lèi)的引用,英寸,野不會(huì)引起內(nèi)存泄漏,經(jīng)典用法的代碼如下。
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
public?class?HandlerAcitivityextends?Activity{
//聲明一個(gè)靜態(tài)的Handler內(nèi)部類(lèi),并持有外部類(lèi)的弱引用
private?static?class?InnerHandlerextends?Handler{
private?final?WeakReference mActivity;
public?InnerHandler(HandlerAcitivity activity){
mActivity =new?WeakReference(activity);
}
public?void?handleMessage(Message msg){
HandlerAcitivity activity = mActivity.get();
if(activity!=null){
//...
}
}
}
private?final?InnerHandler mHandler =new?InnerHandler(this);
//靜態(tài)的匿名內(nèi)部類(lèi)不會(huì)持有外部類(lèi)的引用
private?static?final?Runnable sRunnable =new?Runnable(){
@Override
public?void?run(){
//...
}
};
@Override
protected?void?onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//延遲5分鐘發(fā)送消息
mHandler.postDelay(sRunnable,1000*60*5);
}
}
總結(jié)
以上是生活随笔為你收集整理的java handler的用法_Handler和内部类的正确用法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 埃尔法轮毂重量
- 下一篇: 如何打开php页面跳转_php如何跳转页