android内存泄露:4、Toast的错误使用导致内存泄露

目录

一、前言

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

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

2、写业务逻辑

3、效果展示

4、解决方案


一、前言

上篇文章我们介绍了:Handler的错误使用导致内存泄露详细可参考博文:原创 android内存泄露:3、Handler的错误使用导致内存泄露 ,这篇文章我们将介绍:Toast的错误使用导致内存泄露

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

我们通常,连续点击按钮多次提示的 Toast,它必须等待前面的 Toast显示完了,后面的才能显示出来。

这可能在某种情境下,不是我们想要的。

假如我们想要的结果是:当我点击多次按钮,必须把我最新的 Toast显示出来。

这个时候我们需要去写一个单例的 Toast,但是我们在写的时候,可能会导致我们 Activity的泄露。

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 showToast(View view) {
        startActivity(new Intent(MainActivity.this, ToastActivity.class));
    }

}

activity_main

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

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

</LinearLayout>

2、写业务逻辑

创建一个 Toast的工具类

public class ToastUtils {
    private static Toast sToast;

    public static void showToast(Context context, String msg) {
        if (sToast == null) {
            sToast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
        }

        sToast.setText(msg);
        sToast.show();
    }

}

ToastActivity

public class ToastActivity extends AppCompatActivity {

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

        ToastUtils.showToast(this, new Date().getTime()+"");

    }

}

3、效果展示

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

4、解决方案

/**
 * 如果我们的单例引用到了Activity,那么就会导致Activity无法被GC回收,从而导致内存泄露。
 *
 * 下面代码中sToast是静态的变量,其应用的对象不会被回收,sToast引用到了context,
 * 而 context可能就是Activity的实例,GC无法回收,因此造成Activity的泄露。
 */

解决方式:修改静态单例中对上下文的引用

public class ToastUtils {
    private static Toast sToast;

    public static void showToast(Context context, String msg) {
        if (sToast == null) {
            //sToast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
            
            //我们让静态的Toast引用到全App唯一的一个Application的上下文对象即可
            sToast = Toast.makeText(context.getApplicationContext(), msg, Toast.LENGTH_SHORT);

        }

        sToast.setText(msg);
        sToast.show();
    }

}

有关 Android上下文 比较好的文章:

https://blog.csdn.net/YuDBL/article/details/105575178

sToast 什么时候会被 GC 给回收掉?

sToast 它是一个静态变量,静态的变量属于字节码级别的,字节码一旦被加载了,一般就不会移除了。

加载字节码是类加载器的工作,那么它是不会被 GC 给回收掉的,除非程序退出。

在java里面,类加载器分了好几种,你可以去自定义一个类加载器,它继承于ClassLoader,

当我们自定义的类加载器被卸载掉后,所加载的静态类对象才会被移除掉。

默认情况下,我们都使用系统自带的类加载器,它加载的静态对象,是不会被GC回收掉的。

所以静态变量不是越多越好,它不能够被回收。

注意:

1、之所以不在调用时候改,是因为工具类解决更好,因为在使用过程中可能会忘记这一点

2、虽然不用 static可以避免这个问题,但调用 ToastUtils的时候有点麻烦了

原创文章 365 获赞 60 访问量 18万+

猜你喜欢

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