Android--Handler的内存泄漏原因及解决方法

news/2024/7/7 5:30:36 标签: handler, 内存泄漏, Android

一、如何造成内存泄漏

1、主线程的Looper对象会伴随该应用程序的整个生命周期

2、Java里,非静态内部类匿名类都会潜在引用它们所属的外部类

发送的延迟空消息(EmptyMessageDelayed)后、消息处理被前,该消息会一直保存在主线程的消息队列里持续时间,在持续时间里,该消息内部持有对handler的引用,由于handler属于非静态内部类,所以又持有对其外部类(即MainActivity实例)的潜在引用,引用关系如下图


条引用关系会一直保持直到消息得到处理,从而,这阻止了MainActivity被垃圾回收器(GC)回收,同时造成应用程序的内存泄漏,如下图:


二、解决方法

1、使用静态内部类+弱引用

在Java里,非静态内部类匿名类都会潜在的引用它们所属的外部类。 但是,静态内部类不会。所以,避免内存泄漏的解决方案是:只需要将Handler的子类设置成静态内部类;同时,还可以加上 使用WeakReference弱引用持有Activity实例。

原因:弱引用的对象拥有短暂的生命周期。在垃圾回收器线程扫描时,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

public class MainActivity extends AppCompatActivity {


//将Handler改成静态内部类
     private static class FHandler extends Handler{
      //定义弱引用实例
      private WeakReference<Activity> reference; 

      //在构造方法中传入需要持有的Activity实例
      public MyHandler(Activity activity) { 
      reference = new WeakReference<Activity>(activity); }

        //通过复写handlerMessage()从而决定如何进行更新UI操作
        @Override
        public void handleMessage(Message msg) {
        //省略代码
            }
}

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    //主线程创建时便自动创建Looper和对应的MessageQueue,之前执行Loop()进入消息循环
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    //实例化Handler的子类
    //这里并无指定Looper,即自动绑定当前线程(主线程)的Looper和MessageQueue
        private final Handler showhandler = new FHandler();

         //启动子线程
        new Thread(){
            @Override
            public void run() {
                super.run();
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                 showhandler.sendEmptyMessageDelayed(0x1,10000);

                }
            }
        }.start();
    }

2、 当外部类结束生命周期时清空消息队列

内存泄漏的原因是: 当Activity结束生命周期时,Handler里的Message可能还没处理完,从而导致一系列的引用关系。其实,我们只要在当Activity结束生命周期时清除掉消息队列(MessageQueue)里的所有Message,那么这一系列引用关系就不会存在,就能防止内存泄漏

解决方案:当Activity结束生命周期时(调用onDestroy()方法),同时清除消息队列里的所有回调消息(调用removeCallbacksAndMessages(null))。

@Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
    }




http://www.niftyadmin.cn/n/828867.html

相关文章

kotlin.NotImplementedError: An operation is not implemented: Not yet implemented

开发中用到kotlin出现崩溃&#xff0c;报上面的错&#xff0c;原因如下&#xff1a; 是语法的问题。一般在Java 代码中这样写是不会有问题的&#xff0c;但是在kotlin中就会报错并且导致程序崩溃。 override fun themeFun() { TODO("Not yet implemented") …

Android--HandlerThread详解

一、使用场景 举个例子&#xff0c;数据实时更新&#xff0c;我们每10秒需要切换一下显示的数据&#xff0c;如果我们将这种长时间的反复调用操作放到UI线程中&#xff0c;虽说可以执行&#xff0c;但是这样的操作多了之后&#xff0c;很容易会让UI线程卡顿甚至崩溃。 于是&am…

PAT甲级真题1153

PAT 准考证号由 44 部分组成&#xff1a; 第 11 位是级别&#xff0c;即 T 代表顶级&#xff1b;A 代表甲级&#xff1b;B 代表乙级&#xff1b; 第 2∼42∼4 位是考场编号&#xff0c;范围从 101101 到 999999&#xff1b; 第 5∼105∼10 位是考试日期&#xff0c;格式为年、…

android 子module混淆_Android 代码混淆(二)

文章转自我个人博客Android 代码混淆(一) 中已经记录并走了混淆的整个流程&#xff0c;用命令行进行混淆的操作&#xff0c;并验证了三个过程&#xff0c;这篇文章会记录一下在 Android Studio 下混淆的操作&#xff0c;以及具体需要的注意的一些事项。基本操作及整体的流程1.修…

android 实时监控网络改变

第一步&#xff1a;写一个广播接收类 import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.widget.Toast; public class …

学习

https://github.com/Trinea/android-open-project http://blog.csdn.net/yaozhifeng123456/article/details/48372415 http://blog.csdn.net/yaozhifeng123456/article/details/19617119 https://www.jianshu.com/p/6e5eda3a51af

php adodb5,常用的php ADODB使用方法集锦

ADODB使用方法作者:飞豹游侠 整理&#xff1a;淡水河边//定义数据库变量$DB_TYPE "mysql";$DB_HOST "localhost";$DB_USER "root";$DB_PASS "";$DB_DATABASE "ai-part";require_once("../adodb/a…

PAT甲级真题1042洗牌机(有意思的题)

洗牌就是将一副牌的顺序打乱。 为了防止员工洗牌不够彻底或者员工串通赌徒出老千&#xff0c;许多娱乐场都用自动洗牌机来洗牌。 洗牌机会根据一套随机产生的打乱顺序&#xff0c;将一套牌&#xff08;5454 张&#xff09;进行若干次的洗牌操作。 假设一副牌的最开始时按如下…