簡述
在Android開發的過程中,難免會使用單例模式或者靜態方法工具類.我們會讓它們持有一些外部的Context或者View一般有以下幾種情況:
- 單例模式,類的全局變量持有Context 或 View (注意!持有View和持有Context其實是一樣的) ----->此方式會內存泄露
- 單例模式,方法引入Context ----->此方式不會內存泄露
- 工具類靜態方法持有Context 或 View
- 工具類靜態變量持有Context 或 View
上面我已經說明了會內存泄露的情況,我們就來逐一詳細說明下如何操作,和證明他們是否會內存泄露
Context的類型認識
在講解關於靜態持有Context之前,我們需要來認識一下Context自己的區別,原則上Context其實只有2種(盡管Activity/Fragment/Service/都有Context,但是實際上他們屬於一個類型的Context)
第一種
應用的Context,下面的2行代碼都是調用應用的Context,這個Context在一個app里只會有一個.並且在App啟動時創建,App關閉時消亡,所以這個Context是貫徹App生命周期全程的.
Context applicationContext = getApplicationContext();
Context baseContext = getBaseContext();
第二種
Activity 或者 Service 自己,Activity 或 Service自己本身就是Context,這種Context的生命周期只在Activity或Service的生命周期下,關閉了Activity后Context理所應當的也隨着消亡.有多少Activity和Service就會有多少個Context,並且重復多次創建某個Activity的時候Context也是多個
單例模式持有Context的情況
第一種情況 單例模式,類的變量持有Context 或 View 此方式會內存泄露
首先說明,持有View和持有Context都是一樣的道理,所以我這里就不在驗證持有View的情況
驗證順序是這樣的,我在MainActivity里反復啟動退出TestActivity,然后在TestActivity的onCreate方法里調用單例類並且讓它持有Context,然后我們在用Android studio自帶的內存泄露工具來分析.在這篇中,我將貼全代碼,后續只會將單例類或者工具類貼出.
首先我們創建一個簡單的單例模式,並且讓它的全局變量持有Context
public class SingleMode { private static SingleMode mSingleMode; private Context mContext; private SingleMode(){ } public static synchronized SingleMode I(){ if (mSingleMode == null){ mSingleMode = new SingleMode(); } return mSingleMode; } public void setContext(Context context){ this.mContext = context; } }
然后讓TestActivity里讓調用這個單例類
public class TestActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); SingleMode.I().setContext(this); } }
然后我們在MainActivity里啟動這個TestActivity
public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getName(); private Button btn1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn1 = findViewById(R.id.btn1); btn1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this,TestActivity.class); startActivity(intent); } }); } }
手動反復進出多次,然后我們在退出到MainActivity里,抓取內存泄露信息
從內存泄露分析里,可以看到我已經返回到MainActivity有一段時間了,並且主動手動清理一次內存,但是在查找包下面我們依然可以看到TestActivity在存活,並且存活了多個,而SingleMode在存活是正常的因為靜態存活時間是最長的.換句話說就是因為SingleMode在存活並且持有Context才導致內存泄露了
第二種情況 單例模式,方法引入Context
工具類持有Context的情況
待續...