目录
情形二:在Activity中,使用单例工厂类引用 Activity内部类
1、新建一个 Module,写主界面 MainActivity,布局 activity_main
一、前言
上篇文章我们介绍了:LeakCanary内存泄漏检测库、内存泄露_内存溢出_内存抖动、非静态的内部类错误使用以及解决方式,详细可参考博文:原创 android内存泄露:1、LeakCanary内存泄漏检测库、内存泄露_内存溢出_内存抖动、非静态的内部类错误使用,这篇文章我们将介绍:非静态的内部类错误使用-情形二
二、非静态的内部类错误使用-情形二
情形二:在Activity中,使用单例工厂类引用 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 innerClass(View view) {
startActivity(new Intent(MainActivity.this,InnerClassActivity.class));
}
}
activity_main
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:ignore="MissingConstraints">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="innerClass"
android:text="非静态内部类的错误使用-User" />
</androidx.constraintlayout.widget.ConstraintLayout>
2、写业务逻辑
工具类 UserUtils
public class UserUtils {
private static InnerClassActivity.User sUser;
public static void setsUser(InnerClassActivity.User user) {
sUser = user;
}
}
InnerClassActivity
public class InnerClassActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_inner_class);
//创建的非静态内部类User对象,对外部类(Activity)有隐式的强引用,
//同时该内部类对象又永久被UserUtils静态变量给引用上了,
//从而导致GC想回收该activity的堆内存,发现sUser还在引用,GC无法回收
UserUtils.setsUser(new User("张三"));
}
class User{
private String username;
public User(String username){
this.username = username;
}
}
}
3、效果展示
使用LeakCanary测试的结果如下:
4、解决方案
/**
* 如果Activity中有非静态的内部类,我们创建了这个类的实例对象,
* 但是我们把这个实例对象赋值给了一个单例工厂类,导致该内部类对象的生命周期永远都被引用,
* 同时该对象又引用了Activity,那么就导致了Activity的内存泄露。
*/
解决方式:只需要将内部类User类改为静态内部类即可
静态类对象一旦被jvm(虚拟机)加载,一般是不会被移除掉的,
除非这个虚拟机是我们自定义的虚拟机,也就是我们自己去定义一个类加载器,它继承于ClassLoader,
当我们自定义的类加载器被卸载掉后,所加载的静态类对象才会被移除掉。
默认情况下,我们都使用系统自带的类加载器,它加载的静态对象,是不会被GC回收掉的。
所以让User成为静态类,静态类属于字节码级别的,不再是Activity里面的内部类
当然用静态会有影响
因为这个对象是静态的,那么这个类被加载了,就不会被GC回收释放掉。
但最起码它不会影响 Activity的生命周期,不会影响GC去回收我们这个Activity,
所以应该去慎用,内部类我们也应该去慎用,
这个就需要我们去平衡他们相互之间的关系了。