谈一谈对 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();
		// ...... 
}
  • 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;
}

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); 
}

  • 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;
}

  • 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;
    }
  • 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;
    }
  • 总结
    • 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);
                }
}
  • 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{
    
    
}
  • 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();
    }
  • 看上面的代码可以知道 Service 的流程也差不多,结论

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

BroadcastReceiver

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

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;
    }
	
}
app = data.info.makeApplication(data.restrictedBackupMode, null);

installContentProviders(app, data.providers);

mInstrumentation.callApplicationOnCreate(app);

上面这段代码 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

猜你喜欢

转载自blog.csdn.net/ldxlz224/article/details/127456176