目录
一、前言
二、Toast的错误使用导致内存泄露
1、新建一个 Module,写主界面 MainActivity,布局 activity_main
2、写业务逻辑
3、效果展示
4、解决方案
上篇文章我们介绍了:Handler的错误使用导致内存泄露。详细可参考博文:原创 android内存泄露:3、Handler的错误使用导致内存泄露 ,这篇文章我们将介绍:Toast的错误使用导致内存泄露
我们通常,连续点击按钮多次提示的 Toast,它必须等待前面的 Toast显示完了,后面的才能显示出来。
这可能在某种情境下,不是我们想要的。
假如我们想要的结果是:当我点击多次按钮,必须把我最新的 Toast显示出来。
这个时候我们需要去写一个单例的 Toast,但是我们在写的时候,可能会导致我们 Activity的泄露。
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
创建一个 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()+"");
}
}
类似上几篇文章,使用 LeakCanary工具,会测试到内存泄露的相关信息,这里就不截图和录视频了。
/**
* 如果我们的单例引用到了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的时候有点麻烦了