欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Handler内存泄漏及其解决方案

程序员文章站 2022-04-26 22:29:28
...

几个概念

Java垃圾回收机制(GC)

Java使用自动垃圾回收机制,回收的条件就是对象是否被引用。也就是说如果对象处于不可到达状态就会被回收掉。

Java四种引用

Handler内存泄漏及其解决方案

Activity回收

Activity被销毁的时候在onDestory()方法中,系统销毁了这个Activity的实例在内存中占据的空间。在Activity的生命周期中,onDestory()方法是他生命的最后一步,资源空间等就被回收了。

Handler内存泄漏的原因?

Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        //修改Activity的UI
        mImageView.setImageBitmap(mBitmap);
    }
};
  1. 当使用内部类(包括匿名类)来创建Handler的时候,因为通过Handler来操作Activity中的View,所以Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用。
  2. Handler通常会伴随着一个耗时的后台线程(从网络下载图片),这个后台线程在任务执行完毕之后(图片下载完毕),通过消息机制通知Handler,然后Handler把图片更新到界面。
  3. 如果用户在网络请求过程中关闭了Activity,正常情况下,Activity不再被使用,在onDestory()方法中执行GC检查时就应该被回收掉。但由于这时线程尚未执行完,而该线程持有Handler的引用(不然它怎么发消息给Handler?),这个Handler又持有Activity的引用,就导致该Activity无法被回收,造成内存泄漏,直到网络请求结束(图片下载完毕)。
  4. 如果你执行了Handler的postDelayed()方法,该方法会将你的Handler装入一个Message,并把这条Message推到MessageQueue中,那么在你设定的delay到达之前,会有一条MessageQueue -> Message -> Handler -> Activity的链,导致你的Activity被持有引用而无法被回收。
  5. 同一个Acticity反复进行几次便会程序占用内存超过系统限制,FC。

解决方案

逻辑控制

  1. 在关闭Activity的时候停掉你的后台线程。线程停掉了,就相当于切断了Handler和外部连接的线,Activity自然会在合适的时候被回收。

  2. 如果你的Handler是被delay的Message持有了引用,那么使用相应的Handler的removeCallbacks()方法,把消息对象从消息队列移除就行了。

Handler声明为静态类

静态类不持有外部类的对象,所以你的Activity可以随意被回收,所以不会导致外部类实例出现内存泄露。

static class MyHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        //修改Activity的UI
        mImageView.setImageBitmap(mBitmap);
    }
}

但是,Handler一旦无法持有外部类的对象,就无法修改Activity的View,那么使用Handler就没有意义了。
为了解决这个问题,我们可以在Handler中增加一个对Activity的弱引用(WeakReference):

static class MyHandler extends Handler {
    WeakReference<Activity > mActivityReference;

    MyHandler(Activity activity) {
        mActivityReference= new WeakReference<Activity>(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        final Activity activity = mActivityReference.get();
        if (activity != null) {
            mImageView.setImageBitmap(mBitmap);
        }
    }
}

当Activity finish后 handler对象还是在Message中排队。 还是会处理消息,这些处理有必要?
正常Activitiy finish后,已经没有必要对消息处理,那需要怎么做呢?
解决方案也很简单,在onDestroy的时候,取消掉该Handler对象的Message和Runnable。
removeCallbacks(Runnable r)和removeMessages(int what)等。

@Override
public void onDestroy() {
    //If null, all callbacks and messages will be removed.
    mHandler.removeCallbacksAndMessages(null);
}

参考引用

https://blog.csdn.net/jdsjlzx/article/details/51386440

相关标签: handler OOM