當(dāng)你使用單例類時,Android Studio出現(xiàn)了Do not place Android context classes in static fields; this is a memory leak的內(nèi)存泄漏警告。
public class TestManager {
private Context mContext;
private TestManager() {
}
public void init(Context context) {
mContext = context.getApplicationContext();
Log.d("test", "init " + mContext);
}
public static TestManager getInstance() {
return Holder.INSTANCE;
}
private static class Holder {
private static final TestManager INSTANCE = new TestManager();
}
}

image.png
明明用了context.getApplicationContext()為什么還會出現(xiàn)警告呢?其實(shí)初始化init時傳入Context這種做法是不恰當(dāng)?shù)?,正確應(yīng)該在構(gòu)造方法就傳入Application Context,但是單例類的構(gòu)造方法是是私有的,無法對外傳入Context,怎么辦呢?引用一個全局靜態(tài)的Application Context。
開發(fā)過程中應(yīng)盡量避免傳入Context對象,單例類中的Context對象必須為Application Context,保證在整個應(yīng)用生命周期內(nèi)引用。如下的寫法可以去掉Android Studio內(nèi)存泄漏的警告:
public class TestManager {
private Context mContext;
private TestManager() {
mContext = AppConfigure.getApplicationContext();
}
public void init() {
Log.d("test", "init " + mContext);
}
public static TestManager getInstance() {
return Holder.INSTANCE;
}
private static class Holder {
private static final TestManager INSTANCE = new TestManager();
}
}
這樣Android Studio就不會出現(xiàn)內(nèi)存泄漏的警告了,當(dāng)然可以不用AppConfigure 類來獲取Application Context,可以通過在自定義Application中聲明一個公共靜態(tài)全局的Context供其他類引用。
AppConfigure 類的代碼如下:
public class AppConfigure {
private static volatile Application application;
public static synchronized void configure(Application application) {
AppConfigure.application = application;
}
public static <T extends Application> T getApplication() {
try {
if (application == null) {
synchronized (AppConfigure.class) {
if (application == null) {
@SuppressLint("PrivateApi") Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Method method = activityThreadClass.getMethod("currentActivityThread");
Object localObject = method.invoke(null, (Object[]) null);
Field appField = activityThreadClass.getDeclaredField("mInitialApplication");
appField.setAccessible(true);
application = (Application) appField.get(localObject);
if (application == null) {
Method method2 = activityThreadClass.getMethod("getApplication");
application = (Application) method2.invoke(localObject, (Object[]) null);
}
}
}
}
// noinspection unchecked
return (T) application;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Context getContext() {
return getApplicationContext();
}
public static Context getApplicationContext() {
return getApplication();
}
}