本篇不再去分析Handler Looper MessageQueue 等相關(guān)源碼 為了下面內(nèi)容好理解可以看看我的上兩篇文章
Handler消息機(jī)制
Handler Looper MessageQueue之間的協(xié)作
案例:
public class MainActivity extends AppCompatActivity {
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(0==msg.what){
//xxxxxxxxxx
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler.sendEmptyMessageDelayed(0,10*60*60*1000);
finish();
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Runnable runnable=new Runnable() {
@Override
public void run() {
//xxxxxx
}
};
new Handler().postDelayed(runnable,10*60*60*1000);
finish();
}
}
上面的代碼 在Handler發(fā)送延遲消息后 MainActivity就finish() ,這時Handler卻持有Activity的的引用 導(dǎo)致Activtiy所占內(nèi)存得不到釋放 就造成了內(nèi)存泄漏扎拣。
分析
-
一張圖看懂Handler的發(fā)送消息和處理消息的流程
由上圖可以看出Message全程持有發(fā)送該消息Handler的引用 直到Handler處理完消息 Message回收釋放床蜘。
-
根據(jù)上面兩個案例分析 在Handler發(fā)送一個10分鐘的延遲消息后 Activity就finish() 但是Handler發(fā)送的消息Message卻持有Handler的引用 而Handler卻是在Activtiy中創(chuàng)建的匿名內(nèi)部類對象 在java里尼酿,非靜態(tài)內(nèi)部類 和 匿名類 都會潛在的引用它們所屬的外部類 總結(jié)如下圖:
解決方案:
1.由上分析得出是由匿名內(nèi)部類隱式持有外部類 造成的內(nèi)存泄漏 而在Java中靜態(tài)內(nèi)部類不會持有外部類對象 所以:
public class MainActivity extends AppCompatActivity {
private static class MyHandler extends Handler {
//WeakReference 弱引用
private final WeakReference<MainActivity> mActivity;
public MyHandler(SampleActivity activity) {
mActivity = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = mActivity.get();
if (activity != null) {
// ...
}
}
}
private final MyHandler mHandler = new MyHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler.sendEmptyMessageDelayed(0,10*60*60*1000);
finish();
}
}
public class MainActivity extends AppCompatActivity {
//同理Runnable也屬于匿名類部類 所以也需要聲明為靜態(tài)
private static final Runnable sRunnable = new Runnable() {
@Override
public void run() { /* ... */ }
};
private final MyHandler mHandler = new MyHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler.postDelayed(runnable,10*60*60*1000);
finish();
}
private static class MyHandler extends Handler {
//WeakReference 弱引用
private final WeakReference<MainActivity> mActivity;
public MyHandler(SampleActivity activity) {
mActivity = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = mActivity.get();
if (activity != null) {
// ...
}
}
}
}
最后:
- 上面的案例只是用以做案例分析的 在實(shí)際開發(fā)過程中 我們必須還要在Activity或者Fragment銷毀時清空消息 不然真等到消息回調(diào)的時候 Activity或Fragment已經(jīng)被回收等造成其他異常情況也是不好的
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
}
- 如果一個內(nèi)部類實(shí)例的生命周期比Activity更長挤土,那么我們千萬不要使用非靜態(tài)的內(nèi)部類。最好的做法是纬凤,使用靜態(tài)內(nèi)部類姿搜,然后在該類里使用弱引用來指向所在的Activity。