android内存泄露:3、Handler的错误使用导致内存泄露

目录

一、前言

二、Handler的错误使用导致内存泄露

案例:写一个计时器

1、新建一个 Module,写主界面 MainActivity,布局 activity_main

2、写业务逻辑

3、效果展示

4、解决方案


一、前言

上篇文章我们介绍了:非静态的内部类错误使用_情形二,在Activity中,使用单例工厂类引用 Activity内部类。详细可参考博文:原创 android内存泄露:2、非静态的内部类错误使用_情形二 ,这篇文章我们将介绍:Handler的错误使用导致内存泄露

二、Handler的错误使用导致内存泄露

案例:写一个计时器

1、新建一个 Module,写主界面 MainActivity,布局 activity_main

MainActivity

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void handlerUse(View view) {
        startActivity(new Intent(MainActivity.this, HandlerActivity.class));
    }

}

activity_main

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:text="Handler的错误使用"
        android:onClick="handlerUse"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

2、写业务逻辑

HandlerActivity

public class HandlerActivity extends AppCompatActivity {

    private TextView mTextView;
    private Handler mHandler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);

        mTextView = (TextView) findViewById(R.id.tv_time);

        //1秒之后执行一次以下方法
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //获取当前时间设置为View
                String time = getStringTime();
                mTextView.setText(time);

                //这里的this代表这实现了Runnable接口的匿名内部类对象
                //使得其每隔1秒都会执行该方法
                mHandler.postDelayed(this, 1000);

            }
        }, 1000);

    }


    /**
     * 获取系统时间并格式化
     * @return
     */
    private String getStringTime() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return simpleDateFormat.format(new Date());
    }


}

3、效果展示

类似上两篇文章,使用 LeakCanary工具,会测试到内存泄露的相关信息,这里就不截图和录视频了。

4、解决方案

/**
 * 我们使用Handler发送了循环任务,即:在一个任务执行完前再发送一个同样的任务。这样任务就永远也执行不完。
 *
 * 我们使用Handler发送了Runnable任务,该Runnable任务是一个匿名内部类,对外部类有隐式的强引用,
 * 也就是Runnable对象引用到了Activity,同时Runnable被发送到了MessageQueue中,也就是MessageQueue引用到了Runnable,
 * MessageQueue属于Looper对象的成员变量,因此MessageQueue又被Looper对象引用到,
 * Looper对象是在Looper.prepare()阶段创建并绑定到主线程的
 */

解决方式:当 HandlerActivity销毁的时候,移除当前 mHandler发送的所有的msg消息和任务

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //移除当前 mHandler发送的所有的msg消息和任务
        mHandler.removeCallbacksAndMessages(null);
    }
原创文章 365 获赞 60 访问量 18万+

猜你喜欢

转载自blog.csdn.net/YuDBL/article/details/105568640