Android中Handler引起的内存泄露
2016-01-12 15:55
423 查看
public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override public void handleMessage(Message msg) { // ... } } }
内存泄露的原因
1、当一个android启动的时候,会自动创建一个供应用主线程使用的Looper实例。Looper的主要工作是一个一个处理消息队列中的消息对象。主线程中looper的生命周期和当前应用一样长。
2.当一个Handler在主线程进行了初始化之后,我们发送一个target为这个Handler的消息到Looper处理的消息队列时,实际上已经发送的消息已经包含了一个Handler实例的引用,只有这样Looper在处理到这条消息时才可以调用Handler#handleMessage(Message)完成消息的正确处理。
3.在Java中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用。静态的内部类不会持有外部类的引用。
public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override public void handleMessage(Message msg) { // ... } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Post a message and delay its execution for 10 minutes. mLeakyHandler.postDelayed(new Runnable() { @Override public void run() { /* ... */ } }, 1000 * 60 * 10); // Go back to the previous Activity. finish(); } }
分析一下上面的代码,当我们执行了Activity的finish方法,被延迟的消息会在被处理之前存在于主线程消息队列中10分钟,而这个消息中又包含了Handler的引用,而Handler是一个匿名内部类的实例,其持有外面的SampleActivity的引用,所以这导致了SampleActivity无法回收,进行导致SampleActivity持有的很多资源都无法回收,这就是我们常说的内存泄露。
注意上面的new Runnable这里也是匿名内部类实现的,同样也会持有SampleActivity的引用,也会阻止SampleActivity被回收。
要解决这种问题,思路就是避免使用非静态内部类,继承Handler时,要么是放在单独的类文件中,要么就是使用静态内部类。因为静态的内部类不会持有外部类的引用,所以不会导致外部类实例的内存泄露。当你需要在静态内部类中调用外部的Activity时,我们可以使用弱引用来处理。另外关于同样也需要将Runnable设置为静态的成员属性。注意:一个静态的匿名内部类实例不会持有外部类的引用。 修改后不会导致内存泄露的代码如下
public class SampleActivity extends Activity { /** * Instances of static inner classes do not hold an implicit * reference to their outer class. */ private static class MyHandler extends Handler { private final WeakReference<SampleActivity> mActivity; public MyHandler(SampleActivity activity) { mActivity = new WeakReference<SampleActivity>(activity); } @Override public void handleMessage(Message msg) { SampleActivity activity = mActivity.get(); if (activity != null) { // ... } } } private final MyHandler mHandler = new MyHandler(this); /** * Instances of anonymous classes do not hold an implicit * reference to their outer class when they are "static". */ private static final Runnable sRunnable = new Runnable() { @Override public void run() { /* ... */ } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Post a message and delay its execution for 10 minutes. mHandler.postDelayed(sRunnable, 1000 * 60 * 10); // Go back to the previous Activity. finish(); } }
上面说了很多 其实使用静态Handler的方法调用外部资源方法很简单
private static class MyHandler extends Handler { WeakReference<PickImageActivity> activity = null; public MyHandler(PickImageActivity context) { activity = new WeakReference<PickImageActivity>(context); } @Override public void handleMessage(Message msg) { if (activity.get() == null) return; if (activity.get().gridView.getAdapter() == null) { } else activity.get().adapter.notifyDataSetChanged(); activity.get().gridView.setOnScrollListener(activity.get()); super.handleMessage(msg); } }
相关文章推荐
- Android Mediaplayer设置静音和恢复声音
- Android中保存数据的四种方法
- Android开发
- Android中通过反射和getResource()得到id的方式去改变View的显示效果
- Android 中的SIP协议
- AndroidStudio快捷键
- android的事件分发相关
- [转载]Android SO逆向1 - ARM介绍
- android值得推荐的开源框架简介
- 【android_温故知新】android 数据存储
- Android中的View原理
- 获取Android操作系统源代码
- Android Scroll
- html页面适配android手机兼容问题
- OpenGL ES 2.0 for Android
- android画笔的基本属性
- Android debug.keystore的key和密码
- Android的bitmap遇到内存溢出
- Android greenrobot的EventBus
- android之adapter用法总结