到底getApplicationContext和getApplication是否是返回同一個對象?

前言

在上篇文章從getApplicationContext和getApplication再次梳理Android的Application正確用法中,我提到java

可是咱們知道了mApplication和context是兩個不一樣的東西,因此嚴格意義上來講getApplicationContext和getApplication是不同的,雖然不少時候他們返回的都是同一個對象bash

注意到我這裏說的是這兩個方法返回的對象是不同的,由於我看到Activity中這兩個方法返回了兩個對象,就單純的覺得他們真的是不同的,看來真是淺嘗輒止了,作了個錯誤示範,代碼仍是要刨根問底啊。app

找不一樣

今天來作一個糾正和補充,咱們來繼續往下看代碼,看看他們是否是真的不同,仍是有類似之處:ide

public abstract Context getApplicationContext();
複製代碼

getApplicationContext咱們知道是一個抽象方法,他的真正實現是在ContextImpl中:ui

@Override
    public Context getApplicationContext() {
        return (mPackageInfo != null) ?
                mPackageInfo.getApplication() : mMainThread.getApplication();
    }
複製代碼

再來看看getApplication方法(只存在於Activity和Service中):spa

public final Application getApplication() {
        return mApplication;
    }
複製代碼

那mApplication的賦值在哪?搜索一下,只有一個地方有賦值:.net

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()rest

Application getApplication() {
        return mApplication;
    }
複製代碼

LoadedApk也有一個mApplication,這個mApplication的賦值在LoadedApk的makeApplication:code

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中:orm

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這個類,看到這裏咱們就一目瞭然了,繞來繞去結果都是同一個東西,只是可能建立的時機不一樣,一個是在LoadedApk,一個是在ActivityThread,不過最後咱們發現這個getApplicationContext()返回的都是mApplication

真相大白

這個命名就頗有意思了,在LoadedApk咱們看到了一個叫mApplication的東西,在Activity也有一個叫mApplication,那他們是否是有什麼聯繫呢?來看看在ActivitymApplication的賦值,在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);
...
}
複製代碼

咱們發現又來了。。。熟悉的makeApplication(),r.packageInfo果真是LoadedApk類,最後異曲同工,又來到了這個單例,返回程序惟一的mApplication,仍是同樣的配方。。。

結果

結果很明顯了,標題的問題已解,getApplicationContext和getApplication返回的是否是同一個對象?答:是的!

固然話不能說的那麼死,他們相同的前提是mApplication不爲空,話又說回來,這個是全局的上下文,程序都啓動了他怎麼會爲空呢,至於它到底什麼狀況會爲空形成返回的對象不同呢,待武功精進了繼續分解。。。

相關文章
相關標籤/搜索