前言
在上篇文章從getApplicationContext和getApplication再次梳理Android的Application正確用法中,我提到
但是我們知道了mApplication和context是兩個不同的東西,所以嚴格意義上來說getApplicationContext和getApplication是不一樣的,雖然很多時候他們返回的都是同一個對象
注意到我這里說的是這兩個方法返回的對象是不一樣的,因為我看到Activity中這兩個方法返回了兩個對象,就單純的以為他們真的是不一樣的,看來真是淺嘗輒止了,做了個錯誤示范,代碼還是要刨根問底啊。
找不同
今天來做一個糾正和補充,我們來繼續(xù)往下看代碼,看看他們是不是真的不一樣,還是有相似之處:
public abstract Context getApplicationContext();
getApplicationContext我們知道是一個抽象方法,他的真正實現是在ContextImpl中:
@Override
public Context getApplicationContext() {
return (mPackageInfo != null) ?
mPackageInfo.getApplication() : mMainThread.getApplication();
}
再來看看getApplication方法(只存在于Activity和Service中):
public final Application getApplication() {
return mApplication;
}
那mApplication的賦值在哪?搜索一下,只有一個地方有賦值:
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
attachBaseContext(context);
.......
mApplication = application;
}
在上篇文章中,我看到了這里就覺得這兩個方法返回的對象不一樣,可是我們忽略了getApplicationContext這個方法,當mPackageInfo不為空和為空是分別調用了mPackageInfo.getApplication()和mMainThread.getApplication(),那getApplicationContext到底返回的東西跟mApplication有什么不同,來看看這兩個方法,在LoadedApk.java中看到mPackageInfo.getApplication():
Application getApplication() {
return mApplication;
}
在LoadedApk也有一個mApplication,這個mApplication的賦值在LoadedApk的makeApplication:
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
...
if (mApplication != null) {
return mApplication;
}
Application app = null;
...
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
...
mActivityThread.mAllApplications.add(app);
mApplication = app;
...
}
看到首先是一個空判斷(單例),為空的話新建了一個Application然后賦值給mApplication,我們再看看mMainThread.getApplication()返回了什么,在ActivityThread.java中:
public Application getApplication() {
return mInitialApplication;
}
再來看看mInitialApplication的賦值在哪里:
private void handleBindApplication(AppBindData data) {
...
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
...
}
我們又看到了makeApplication,至于data.info也是LoadedApk這個類,看到這里我們就一目了然了,繞來繞去結果都是同一個東西,只是可能創(chuàng)建的時機不同,一個是在LoadedApk,一個是在ActivityThread,不過最后我們發(fā)現這個getApplicationContext()返回的都是mApplication。
真相大白
這個命名就很有意思了,在LoadedApk我們看到了一個叫mApplication的東西,在Activity也有一個叫mApplication,那他們是不是有什么聯(lián)系呢?來看看在Activity中mApplication的賦值,在attach方法中找到了它(方法中的其他參數我去掉了):
final void attach(Application application) {
mApplication = application;
}
也就是說等于調用attach方法時傳入的application,那Activity的attach是在哪里調用呢,我們要來到反復提到的一個應用程序入口類ActivityThread,它有一個performLaunchActivity的方法,用來加載一個Activity,這里就有attach()的調用(我去掉了其他參數):
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
activity.attach(app);
...
}
我們發(fā)現又來了。。。熟悉的makeApplication(),r.packageInfo果然是LoadedApk類,最后殊途同歸,又來到了這個單例,返回程序唯一的mApplication,還是一樣的配方。。。
結果
結果很明顯了,標題的問題已解,getApplicationContext和getApplication返回的是不是同一個對象?答:是的!
當然話不能說的那么死,他們相同的前提是mApplication不為空,話又說回來,這個是全局的上下文,程序都啟動了他怎么會為空呢,至于它到底什么情況會為空造成返回的對象不一樣呢,待武功精進了繼續(xù)分解。。。