前言
在上篇文章從getApplicationContext和getApplication再次梳理Android的Application正確用法中,我提到
但是我們知道了mApplication和context是兩個(gè)不同的東西,所以嚴(yán)格意義上來(lái)說(shuō)getApplicationContext和getApplication是不一樣的,雖然很多時(shí)候他們返回的都是同一個(gè)對(duì)象
注意到我這里說(shuō)的是這兩個(gè)方法返回的對(duì)象是不一樣的,因?yàn)槲铱吹紸ctivity中這兩個(gè)方法返回了兩個(gè)對(duì)象,就單純的以為他們真的是不一樣的,看來(lái)真是淺嘗輒止了,做了個(gè)錯(cuò)誤示范,代碼還是要刨根問(wèn)底啊。
找不同
今天來(lái)做一個(gè)糾正和補(bǔ)充,我們來(lái)繼續(xù)往下看代碼,看看他們是不是真的不一樣,還是有相似之處:
public abstract Context getApplicationContext();
getApplicationContext我們知道是一個(gè)抽象方法,他的真正實(shí)現(xiàn)是在ContextImpl中:
@Override
public Context getApplicationContext() {
return (mPackageInfo != null) ?
mPackageInfo.getApplication() : mMainThread.getApplication();
}
再來(lái)看看getApplication方法(只存在于Activity和Service中):
public final Application getApplication() {
return mApplication;
}
那mApplication的賦值在哪?搜索一下,只有一個(gè)地方有賦值:
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;
}
在上篇文章中,我看到了這里就覺(jué)得這兩個(gè)方法返回的對(duì)象不一樣,可是我們忽略了getApplicationContext這個(gè)方法,當(dāng)mPackageInfo不為空和為空是分別調(diào)用了mPackageInfo.getApplication()和mMainThread.getApplication(),那getApplicationContext到底返回的東西跟mApplication有什么不同,來(lái)看看這兩個(gè)方法,在LoadedApk.java中看到mPackageInfo.getApplication():
Application getApplication() {
return mApplication;
}
在LoadedApk也有一個(gè)mApplication,這個(gè)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;
...
}
看到首先是一個(gè)空判斷(單例),為空的話新建了一個(gè)Application然后賦值給mApplication,我們?cè)倏纯磎MainThread.getApplication()返回了什么,在ActivityThread.java中:
public Application getApplication() {
return mInitialApplication;
}
再來(lái)看看mInitialApplication的賦值在哪里:
private void handleBindApplication(AppBindData data) {
...
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
...
}
我們又看到了makeApplication,至于data.info也是LoadedApk這個(gè)類,看到這里我們就一目了然了,繞來(lái)繞去結(jié)果都是同一個(gè)東西,只是可能創(chuàng)建的時(shí)機(jī)不同,一個(gè)是在LoadedApk,一個(gè)是在ActivityThread,不過(guò)最后我們發(fā)現(xiàn)這個(gè)getApplicationContext()返回的都是mApplication。
真相大白
這個(gè)命名就很有意思了,在LoadedApk我們看到了一個(gè)叫mApplication的東西,在Activity也有一個(gè)叫mApplication,那他們是不是有什么聯(lián)系呢?來(lái)看看在Activity中mApplication的賦值,在attach方法中找到了它(方法中的其他參數(shù)我去掉了):
final void attach(Application application) {
mApplication = application;
}
也就是說(shuō)等于調(diào)用attach方法時(shí)傳入的application,那Activity的attach是在哪里調(diào)用呢,我們要來(lái)到反復(fù)提到的一個(gè)應(yīng)用程序入口類ActivityThread,它有一個(gè)performLaunchActivity的方法,用來(lái)加載一個(gè)Activity,這里就有attach()的調(diào)用(我去掉了其他參數(shù)):
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
activity.attach(app);
...
}
我們發(fā)現(xiàn)又來(lái)了。。。熟悉的makeApplication(),r.packageInfo果然是LoadedApk類,最后殊途同歸,又來(lái)到了這個(gè)單例,返回程序唯一的mApplication,還是一樣的配方。。。
結(jié)果
結(jié)果很明顯了,標(biāo)題的問(wèn)題已解,getApplicationContext和getApplication返回的是不是同一個(gè)對(duì)象?答:是的!
當(dāng)然話不能說(shuō)的那么死,他們相同的前提是mApplication不為空,話又說(shuō)回來(lái),這個(gè)是全局的上下文,程序都啟動(dòng)了他怎么會(huì)為空呢,至于它到底什么情況會(huì)為空造成返回的對(duì)象不一樣呢,待武功精進(jìn)了繼續(xù)分解。。。