• 谈一谈对 Android Context 的理解


    Context 的作用

    /**
     * Interface to global information about an application environment.  This is
     * an abstract class whose implementation is provided by the Android system.  It
     * allows access to application-specific resources and classes, as well as
     * up-calls for application-level operations such as launching activities,
     * broadcasting and receiving intents, etc.
     * Context 是一个抽象类,由android系统提供的,它允许获取一些资源和类,并且可以用来启动activity broadcasting,接受 intexts等。。。
     */
    public abstract class Context {
    	public abstract Resources getResources();
        /** Return PackageManager instance to find global package information. */
        public abstract PackageManager getPackageManager();
        /** Return a ContentResolver instance for your application's package. */
        public abstract ContentResolver getContentResolver();
    	public abstract AssetManager getAssets();
    	public abstract Context getApplicationContext();
    		// ...... 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • Context 的实现类是 ContextImpl,其内部有很多系统的服务,正是有了这些 Activity 等组件才可以调用系统服务,比如获取系统资源,主题 包管理等。
    class ContextImpl extends Context {
    	    @UnsupportedAppUsage
        final @NonNull ActivityThread mMainThread;
        @UnsupportedAppUsage
        final @NonNull LoadedApk mPackageInfo;
        @UnsupportedAppUsage
        private @Nullable ClassLoader mClassLoader;
        private @NonNull Resources mResources;
        private Resources.Theme mTheme = null;
        @UnsupportedAppUsage
        private PackageManager mPackageManager;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Context 有几种,它们是怎么被创建的。

    • Application、Activity、Service 是有自己的 Context 的
    • BroadcastReceiver和ContentProvider是没有自己的 Context 的。

    Application

    • Application 的 Context 在之前有详细说过创建流程。其中Application的创建是随着应用创建而创建的,进程启动后会执行ActivityThread的 main() 函数,通知 AMS 创建完成,AMS会发送消息通知创建 Application 对象,代码如下:
    • Handler 接收到消息后调用 handleBindApplication() ,通过 makeApplication 创建对象,然后调用 callApplicationOnCreate()
    private void handleBindApplication(AppBindData data) {
    	// 获取 data.info 描述应用安装包信息的对象 data.info 就是 LoadedApk
    	data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
    	//。。。
    	Application app;
    	// 通过 makeApplication 方法创建 Application 对象
        app = data.info.makeApplication(data.restrictedBackupMode, null);
        // 。。。
        // 调用 Application 的 onCreate() 函数
         mInstrumentation.callApplicationOnCreate(app); 
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • makeApplication() 其中先创建了 ContextImpl 再创建Application时传入了 ContextImpl对象。
    public Application makeApplication(boolean forceDefaultAppClass,Instrumentation instrumentation) {
    	if (mApplication != null) {
    		return mApplication;
    	}
    	final java.lang.ClassLoader cl = getClassLoader();
    	// 为 Application 创建一个 Context
    	ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
    	// 为 Application 创建对象 传入了 appContext;所以 Application 的 Context 的实现类是 ContextImpl
    	app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
    	return app;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • newApplication()
        public Application newApplication(ClassLoader cl, String className, Context context)
                throws InstantiationException, IllegalAccessException, 
                ClassNotFoundException {
                // instantiateApplication 内部通过ClassLoader反射创建 application 对象
            Application app = getFactory(context.getPackageName())
                    .instantiateApplication(cl, className);
                    // 调用 attch 里面会把 Context 赋值给 mBase ;attach 会调用 attachBaseContext() 
            app.attach(context);
            return app;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • app.attach 调用了 attachBaseContext() ,把刚才创建的 ContextImpl 赋值给 mBase;同时可以看到 getBaseContext() 获取的就是 mBase; ContextWrapper 本身就是一个 Context 对象,但是 mBase 也是一个 Context 对象,ContextWrapper 也就是 Application 把 功能都代理给了 mBase 去处理。
        protected void attachBaseContext(Context base) {
            if (mBase != null) {
                throw new IllegalStateException("Base context already set");
            }
            mBase = base;
        }
    
        /**
         * @return the base context as set by the constructor or setBaseContext
         */
        public Context getBaseContext() {
            return mBase;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 总结
      • plication 继承自 ContextWrapper 继承自 Context
      • 调用顺序:看上面的流程,是先创建的对象,也就是构造函数最先运行,然后调用的 attachBaseContext() 然后调用的 onCreate() 。
      • ContextWrapper 中传入了一个 Context ,所有功能都代理给了 mBase 这个 Context

    Activity

    • Activity 的 Context 是怎么初始化的
      activity 启动流程很复杂,最终会调用到 ActivityThread 中的 performLaunchActivity() 方法,看看内部是如何操作的。
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    	// ...
    	    ContextImpl appContext = createBaseContextForActivity(r);
            Activity activity = null;
            // 通过反射创建 Activity 对象 
            activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    		// 创建 application 对象,如果创建过则直接返回
    		Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    		// 调用 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, r.configCallback,
                            r.assistToken);
    				// 设置主题
                    int theme = r.activityInfo.getThemeResource();
                    if (theme != 0) {
                        activity.setTheme(theme);
                    }
    
                    activity.mCalled = false;
                    // 调用 onCreate() 方法
                    if (r.isPersistable()) {
                        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                    } else {
                        mInstrumentation.callActivityOnCreate(activity, r.state);
                    }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • Activity 继承自 ContextThemeWrapper ,ContextThemeWrapper 继承自 ContextWrapper 然后继承自 Context 。当Activity 调用 attach 以后还是会调用 attachBaseContext() 调用到的就是 Context 的 attachBaseContext() 依然是和 Applocation 一样通过 mBase 代理。最后会调用 onCreate() 方法。(ContextThemeWrapper 比 ContextWrapper 多了主题的内容,因为 Application 是没有页面展示的所以直接继承了 ContextWrapper)

    • 总结

    • 继承关系:Activity <— ContextThemeWrapper <— ContextWrapper <— Context
    • 调用顺序:先构造器 -> attachBaseContext() -> onCreate()

    Service

    public abstract class Service extends ContextWrapper{
    }
    
    • 1
    • 2
    • ActivityThread 的 handleCreateService()
        private void handleCreateService(CreateServiceData data) {
    
    			Service service = null;
                ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
                Application app = packageInfo.makeApplication(false, mInstrumentation);
                java.lang.ClassLoader cl = packageInfo.getClassLoader();
                service = packageInfo.getAppFactory()
                        .instantiateService(cl, data.info.name, data.intent);
    			service.attach(context, this, data.info.name, data.token, app,
                        ActivityManager.getService());
                service.onCreate();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 看上面的代码可以知道 Service 的流程也差不多,结论

    先 new 对象,然后 attachBaseContext 然后 onCreate()

    BroadcastReceiver

    public abstract class BroadcastReceiver {
     public abstract void onReceive(Context context, Intent intent);
    }
    
    • 1
    • 2
    • 3

    BroadcastReceiver 是没有继承其他的类的,在他的onReceive() 方法中有一个 Context,如果是动态注册则调用者是谁这个 Context 是谁,如果是静态注册的,则 context 就是以 Application 为 mBase 的 ContextWrapper

    ContentProvider

    public abstract class ContentProvider implements ContentInterface, ComponentCallbacks2 {
        @UnsupportedAppUsage
        private Context mContext = null;
    		// 构造函数传入的 mContext ,实际上就是 ApplicationContext 
    	    public ContentProvider(
                Context context,
                String readPermission,
                String writePermission,
                PathPermission[] pathPermissions) {
            mContext = context;
        }
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    app = data.info.makeApplication(data.restrictedBackupMode, null);
    
    installContentProviders(app, data.providers);
    
    mInstrumentation.callApplicationOnCreate(app);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    上面这段代码 makeApplication 时传入的第二个参数是 Instrumentation 对象,传入的是 null ,所以其内部的 mInstrumentation.callApplicationOnCreate(app); 代码没有走,所以创建完成 application 对象 并调用了 attach 后,创建的 ContentProvider ,然后再调用的 mInstrumentation.callApplicationOnCreate(app); 所以ContentProvider 的 onCreate() 是比 callApplicationOnCreate 先执行的。

    问题

    • 应用里面有多少Context,不同 Context 之间有什么区别?

    应用里 Activity Service 和 Application 有 Context ,所以应用中有多少个这几个组件就有多少个 Context 。区别:Activity 因为有 显示UI,所以继承 ContextThemeWrapper ,其他两个继承 ContextWrapper 。

    Activity 里面的 this 和 getBaseContext 有什么区别
    this 就是Activity自己的对象,是返回 mBase 对象是 ContextImpl ;

    getApplication 和 getApplicationContext 有什么区别
    他们俩都是返回 Application 对象,getApplicationContext 是 Context 的抽象函数,但是 getApplication 只有 Activity 和 Service 独有的。因为 Activity 初始化时绑定了 Application ,广播时传入的 Context ,只能获取到 getApplicationContext。

    应用组件的构造器、onCreate、attachBaseContext 调用顺序
    先 构造器 —> attachBaseContext —> onCreate

  • 相关阅读:
    前端面试题——JavaScript 高频
    【推荐系统】DeepFM模型
    [THUPC2022决赛] rsraogps
    最好的前端框架
    Redis五大基本数据类型
    老友记第二季5集背诵句
    npm的基础
    【背景调查】企业HR自主操作背调都有哪些“坑”?这份避坑指南请收好!
    软件之间沟通的大喇叭:Android四大组件之广播机制
    当新技术开始成熟,特别是AI、区块链、虚拟现实等新技术不断地扩大范围
  • 原文地址:https://blog.csdn.net/ldxlz224/article/details/127456176