getApplicationContext 详解

getApplicationContext 详解

1.首先我们先要知道Activity 父亲是Context ,Context 是个抽象类,ContextImpl 是Context 具体实现类.ContextWrapper也是继承于Context ,ContextWrapper使用代理方式调用ContextImpl.

2.想了解系统相关的知识,必须先要熟悉系统运行流程,系统是如何启动,如何为我们创建UI线程.

这里先简单的介绍下,

系统启动的先后顺序 android init进程-->Zygote进程-->SystemServer 等.我们这次主要从SystemServer中来进行介绍,SystemServer中main函数;

/Android/Sdk/sources/android-25/com/android/server/SystemServer.java
/**
 * The main entry point from zygote.
 */
public static void main(String[] args) {
    new SystemServer().run();
}
private void run() {
    try {
        // 初始化系统Context
        createSystemContext();
        ...............
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    }
}

private void createSystemContext() {
    //创建 ActivityThread
    ActivityThread activityThread = ActivityThread.systemMain();
   //执行 ActivityThread.getSystemContext()方法
    mSystemContext = activityThread.getSystemContext();
    mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
}
/Android/Sdk/sources/android-25/android/app/ActivityThread.java

//ActivityThread 的 getSystemContext
public ContextImpl getSystemContext() {
    synchronized (this) {
        if (mSystemContext == null) {
       //创建系统ContextImpl 并将当前ActivityThread传到ContextImpl
            mSystemContext = ContextImpl.createSystemContext(this);
        }
        return mSystemContext;
    }
}

创建ContextImpl 并将当前ActivityThread传到ContextImpl

/Android/Sdk/sources/android-25/android/app/ContextImpl.java

static ContextImpl createSystemContext(ActivityThread mainThread) {
    //创建 LoadedApk
    LoadedApk packageInfo = new LoadedApk(mainThread);
   //创建 ContextImpl
    ContextImpl context = new ContextImpl(null, mainThread,
            packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
    context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
            context.mResourcesManager.getDisplayMetrics());
    return context;
}
class ContextImpl extends Context {

    final ActivityThread mMainThread;

    final LoadedApk mPackageInfo;

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

}

在ContextImpl 中发现了getApplicationContext()方法,刚才说了Activity是Context 的子类ContextImpl是Context具体实现类,所以我们通过在Acitivty中调用getApplicationContext()是通过ContextWrapper 代理的方式调用ContextImpl的getApplicationContext() ,getApplicationContext()方法是先判断mPackageInfo 不是空的情况下 mPackageInfo.getApplication() 否则mMainThread.getApplication(),在看下mPackageInfo.getApplication()是如何调用的如下:


/Android/Sdk/sources/android-25/android/app/LoadedApk.java

Application getApplication() {
    return mApplication;
}

接下来看下LoadedApk中如何给 mApplication 赋值的如下:

public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    if (mApplication != null) {
        return mApplication;
    }

    Application app = null;

    String appClass = mApplicationInfo.className;
    if (forceDefaultAppClass || (appClass == null)) {
        appClass = "android.app.Application";
    }

    try {
        java.lang.ClassLoader cl = getClassLoader();
      
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);
        appContext.setOuterContext(app);
    } catch (Exception e) {
   
    }

    mApplication = app;

  
  
    return app;
}

是通过makeApplication方法,makeApplication 方法是在 ActivityThread 的 performLaunchActivity执行的方法的,就是说每次Launch启动 调用performLaunchActivity方法makeApplication方法创建Application并赋值给 getApplicationContext.makeApplication先判断mApplication不等于空返回mApplication 否则通过反射 "android.app.Application" 创建Application并执行attach方法如下:

/Android/Sdk/sources/android-25/android/app/Application.java

/* package */ final void attach(Context context) {
    attachBaseContext(context);
    mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}

attach 是final 不能被重写.attachBaseContext(context)是可以重写的如下

/**
 * Set the base context for this ContextWrapper.  All calls will then be
 * delegated to the base context.  Throws
 * IllegalStateException if a base context has already been set.
 * 
 * @param base The new base context for this wrapper.
 */
protected void attachBaseContext(Context base) {
    if (mBase != null) {
        throw new IllegalStateException("Base context already set");
    }
    mBase = base;
}

 

这里在介绍一下 getApplicationContext() 和 getApplication() 区别 我们知道getApplicationContext()是通makeApplication 方法进行赋值的,通过反射 "android.app.Application" . 但是getApplication()是如何赋值的那?,在调用getApplication()如下:

/** Return the application that owns this activity. */
public final Application getApplication() {
    return mApplication;
}

直接返回一个Application,在Acitvity 方法 attach 方法中看到了application进行赋值如下:

/Android/Sdk/sources/android-25/android/app/Activity.java

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,
        Window window) {
    attachBaseContext(context);
    mUiThread = Thread.currentThread();

    mMainThread = aThread;
    mInstrumentation = instr;
    mToken = token;
    mIdent = ident;
    //mApplication 赋值
    mApplication = application;
}

attach执行传过来application,前面说过Application创建在ActivityThread 的 performLaunchActivity执行的,就是说每次Launch启动 调用performLaunchActivity方法makeApplication方法创建Application.performLaunchActivity如下:

/Android/Sdk/sources/android-25/android/app/ActivityThread.java

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

    Activity activity = null;

     //创建Application
        Application app = r.packageInfo.makeApplication(false, mInstrumentation)

        if (activity != null) {
         //执行 activity.attach 方法
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config,
                    r.referrer, r.voiceInteractor, window);
         
    return activity;
}

调用performLaunchActivity执行makeApplication 创建Application 并赋值getApplicationContext().

这里我们看到了 activity.attach(app) 这里的app 就是一个Application 也是通过makeApplication创建的.

最后 通过我们的分析不管是 getApplicationContext() 和 getApplication() 都是通过makeApplication创建的 ,所以说你使用getApplicationContext()还是getApplication()它俩返回的都是一个对象.

在使用中发现 getApplicationContext()是在Context 定义的,所以说只要继承Context的子类都可以调用getApplicationContext()方法.

但是getApplication() 在Context并没有定义,只是在Activity和Service中定义了getApplication()方法 并在创建ActivityThread 的 performLaunchActivity方法中执行 makeApplication方法创建Application然后使用activity.attach(app)进行的赋值的.

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值