Android常用编程中,Handler在进行异步操作并处理返回结果时,经常被使用。通常我们的代码会这样实现。
public class MainActivity extends Activity{
private final Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg){
//....
}
}
}
但是,上面的代码是可能导致内存泄露的,代码中哪里可能导致内存泄露呢。又是如何导致内存泄露的呢?我们接下来就慢慢分析下。
1.当一个Android应用启动的时候,会自动创建一个供应用主线程使用的Looper实例。Looper的主要工作就是一个一个处理消息队列中的消息对象。在Android框架的事件(比如Activity的生命周期方法调用,和按钮点击等)都是放入到消息中)然后加入到Looper要处理的消息队列中,由Looper负责一条一条的进行处理。主线程中的Looper生命周期和当前应用一样长。
2.当一个Handler在主线程进行初始化之后,我们发送了一个target为这个Handler的消息到Looper处理的消息队列时,实际上已经发送的消息已经包含了一盒Handler实例的引用,只有这样的Looper在处理到这条消息时,Handler调用handleMessage()Looper才会去处理Message。
3.在java中,非静态的内部类和匿名内部类都会隐式的持有其外部类的引用。静态的内部类不会持有外部类的引用。(在内部类构造的时候,会将外部类的引用传递进来,并且作为内部类的一个属性,所以内部类会持有一个其外部类的引用。)
在上面的例子中有点难以察觉内存泄露,那么下面的例子就非常的明显了。
private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; @Override public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) { super.onCreate(savedInstanceState, persistentState); mHandler.postDelayed(new Runnable() { @Override public void run() { } },1000 * 60); finish(); }
分析上面的代码,我们执行了finsh();被延迟的消息会在被处理之前存在于,主线程消息队列中10分钟,而这个消息中又包含了handler的引用,而handler又是一个匿名内部类的实例,其持有外面的activity的引用,所以activity中很多资源无法回收,这就是我们常说的内存泄露。
要解决这种问题,思路就是避免使用非静态内部类,继承Handler时,要么是放在单独的类文件中,要么就是使用静态内部类。因为静态的内部类不会持有外部类的引用,所以不会导致外部类的实例内存泄露。当你需要在静态内部类中调用外部的activty时,我们可以使用弱引用来处理。另外关于同样需要将Runnable设置为静态的成员属性,注意;一个静态的匿名内部类实例不会持有外部类的引用。修改后不会导致内存泄露。
private static class MyHandler extends Handler{ private final WeakReference<MainActivty> mWeakReference; private MyHandler(MainActivty mainActivty) { mWeakReference = new WeakReference<MainActivty>(mainActivty); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); MainActivty mainActivty = mWeakReference.get(); if(mainActivty != null){ // } } } private final MyHandler mMyHandler = new MyHandler(this); public static Runnable sRunnable = new Runnable() { @Override public void run() { // } }; @Override public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) { super.onCreate(savedInstanceState, persistentState); mMyHandler.postDelayed(sRunnable,1000 * 60); finish(); }
内部类构造外部类传引用:http://droidyue.com/blog/2014/10/02/the-private-modifier-in-java/