Android 常见的几种内存泄漏 - Handler
2017-06-09 13:18
218 查看
Handler的使用造成的内存泄漏问题应该说最为常见了,平时在处理网络任务或者封装一些请求回调等api都应该会借助Handler来处理,对于Handler的使用代码编写一不规范即有可能造成内存泄漏,如下示例:
这种创建Handler的方式会造成内存泄漏,由于mHandler是Handler的匿名内部类的实例,所以它持有外部类Activity的引用,我们知道消息队列是在一个Looper线程中不断轮询处理消息,那么当这个Activity退出时消息队列中还有未处理的消息或者正在处理消息,而消息message持有mHandler实例的引用,mHandler又持有Activity的引用,所以导致该Activity的内存资源无法及时回收,引发内存泄漏。
那怎么样才可以避免这中问题呢,这里提供两个解决方案。这个问题是由于当Activity被销毁时发现引用它的Handler还在,从而导致了GC无法回收Activity。那么最简单最直接的方法是在Activity的OnDestory方法中移除所有的消息和回调即清空队列,MessageQueue被释放 从而使Handler得到释放,这时GC就能正常回收被销毁的Activity了。所以这种解决方案方法如下:
这个解决方案我们忽略了消息队列的作用。由于Handler对于Activity的引用导致GC无法回收Activity,我们直接暴力的把消息队列清空了,那如果需要这些处理消息队列中的消息呢?这就需要用到我们第二个解决方案:弱引用。其原理就是让所有在handler里面使用的对象都变成弱引用,目的就是为了可以在Android回收内存的时候,可以直接回收掉。
public class MainActivity extends AppCompatActivity { private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { //... } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); loadData(); } private void loadData(){ //...request Message message = Message.obtain(); mHandler.sendMessage(message); } }
这种创建Handler的方式会造成内存泄漏,由于mHandler是Handler的匿名内部类的实例,所以它持有外部类Activity的引用,我们知道消息队列是在一个Looper线程中不断轮询处理消息,那么当这个Activity退出时消息队列中还有未处理的消息或者正在处理消息,而消息message持有mHandler实例的引用,mHandler又持有Activity的引用,所以导致该Activity的内存资源无法及时回收,引发内存泄漏。
那怎么样才可以避免这中问题呢,这里提供两个解决方案。这个问题是由于当Activity被销毁时发现引用它的Handler还在,从而导致了GC无法回收Activity。那么最简单最直接的方法是在Activity的OnDestory方法中移除所有的消息和回调即清空队列,MessageQueue被释放 从而使Handler得到释放,这时GC就能正常回收被销毁的Activity了。所以这种解决方案方法如下:
@Override protected void onDestroy() { super.onDestroy(); mHandler.removeCallbacksAndMessages(null); }
这个解决方案我们忽略了消息队列的作用。由于Handler对于Activity的引用导致GC无法回收Activity,我们直接暴力的把消息队列清空了,那如果需要这些处理消息队列中的消息呢?这就需要用到我们第二个解决方案:弱引用。其原理就是让所有在handler里面使用的对象都变成弱引用,目的就是为了可以在Android回收内存的时候,可以直接回收掉。
public class MainActivity extends AppCompatActivity { private MyHandler mHandler = new MyHandler(this); private TextView mTextView ; private static class MyHandler extends Handler { private WeakReference<Context> reference; public MyHandler(Context context) { reference = new WeakReference<>(context); } @Override public void handleMessage(Message msg) { MainActivity activity = (MainActivity) reference.get(); if(activity != null){ activity.mTextView.setText(""); } } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView)findViewById(R.id.textview); loadData(); } private void loadData() { //...request Message message = Message.obtain(); mHandler.sendMessage(message); } }
相关文章推荐
- Android的Handler几种常见的传值方式
- Android开发之Handler(五)几种常见的传值方式
- Android的Handler几种常见的传值方式
- Android常见的几种内存泄漏小结
- Android 几种常见的内存泄漏
- Android开发常见问题之Handler引起的内存泄漏
- Android 常见的几种内存泄漏 - Timer
- Android常见的几种内存泄漏小结
- Android几种常见的内存泄漏
- Android的Handler几种常见的传值方式
- Android开发之Handler(五)几种常见的传值方式
- App工程结构搭建:几种常见Android代码架构分析
- android几种常见的启动模式
- App工程结构搭建:几种常见Android代码架构分析
- Android下常见的内存泄漏
- [Android开发常见问题-23] Android Handler、Message完全解析,带你从源码的角度彻底理解
- Android项目-几种常见的应用架构
- android 4.2 SMS常见数据监听, 更新方式, ContentObserver, CursorLoader,AsyncQueryHandler
- 关于android几种常见的UI综合
- [整理]android中几种常见的尺寸