目錄
情形二:在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,
所以應該去慎用,內部類我們也應該去慎用,
這個就需要我們去平衡他們相互之間的關係了。