Android中this和getApplicationContext()两种上下文的区别、getApplicationContext 详解

时间:2021-7-4 作者:qvyue

版权

#两种上下文的区别#

1.getApplicationContext()  返回Context 

2.activity.this   代表的就是当前的activity,继承context,父类当中有的方法子类中一定有,子类中有的方法父类中不一定有,在用getApplicationContext()一定能使用activity.this,但是能用activity.this不一定能使用getApplicationContext()

3.报错:android.view.WindowManager$BadTokenException: Unable to add window — token null is not for an application  没有添加窗口,

4.在使用对话框的时候,必须告诉对话框,要挂载哪个activity,也是告诉对话框应用在哪个activity中显示

5.在使用跟对话框相关的操作的时候必须使用activity.this不能使用getApplicationContext()

6.getContext() : 返回Context ,一般用在单元测试中或者是自定义控件,其实和getApplicationContext()一样操作

7.this:代表当前,在Activity当中就是代表当前的Activity,换句话说就是Activity.this在Activity当中可以缩写为this;getApplicationContext():生命周期是整个应用,应用摧毁,它才摧毁,能用getApplicationContext()的,百分百能用this,但是反过来不一定可以

原文链接:https://blog.csdn.net/zwj540469505/article/details/51420070

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)进行的赋值的.

原文链接:https://blog.csdn.net/qianxiangsen/article/details/81328080

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。