[framework]了解android的各种Context

前提概要

首先先上一个类关系图看看。
在这里插入图片描述

context.java是一个抽象类,定义了context主要的功能方法。
具体context的实现类是contextImpl.java,而ContextWrapper.java里维护着的mBase对象实际是ContextImpl的实例对象。
而Application activity Service都是继承了ContextWrapper或是ContextWrapper的子类。

context、contextImpl、ContextWrapper这三者的关系在设计者模式中的装饰模式。

<<<<<<<<<<<<<<小插曲<<<<<<<<<<<<<
回顾下装饰者模式的类图demo

在这里插入图片描述

下面展示一些

public class DecoratorTest {  
  
    public static void main(String[] args) {  
        Sourceable source = new Source();  
        Sourceable obj = new Decorator(source);  
        obj.method();  
    }  
}  

<<<<<<<<<<<<<<小插曲 结束<<<<<<<<<<<<<

介绍完Context ContexImpl ContextWrapper三者的关系,接下来就到了,

Service、Activity、 Application、 BroadcastReceiver、 ContentProvider如何与Context 联动起来,可以从初始化组件流程时逐一击破。

Activity Context

activity的启动中有:

 @Override
    public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
...
//构建activity对象
final Activity a = performLaunchActivity(r, customIntent);
...
}

再看看performLaunchActivity方法,这里可以看到
1.从新建Context,
2.实例化Activity,
3.将Context和Activity关联:

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
 ...
 //参数r是ActivityClientRecord,
 //里面有目的activity的基本信息(intent),包信息(packageInfo:LoadedApk )等等
  //为目的的activity新建一个contextImpl对象appContext
 ContextImpl appContext = createBaseContextForActivity(r);

 Activity activity = null;
        try {
        	//获取classLoader,用于实例化activity
            java.lang.ClassLoader cl = appContext.getClassLoader();
            //在Instrumentation 实例化activity:
	            //1.获取activityThread的LoadApk对象
	            //2.获取LoadApk里的AppComponentFactory变量,
	            //3.通过AppComponentFactory里instantiateActivity()方法,利用类加载器和目的类名实例化该activity
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } 
		 ...
 				
 				Window window = null;
                if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                //将待移除的window赋给新的window后,LoadApk对象删去mPendingRemoveWindow的内容
                    window = r.mPendingRemoveWindow;
                    r.mPendingRemoveWindow = null;
                    r.mPendingRemoveWindowManager = null;
                }
                //设置取Context对象时的返回的内容(getOuterContext)
                // (Activity类继承了Context类,故可传入activity)
                appContext.setOuterContext(activity);
                //将activity与context绑定关系
                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);

 ...
 }

再来康康上面的关键方法
[1.从新建Context]
createBaseContextForActivity:

 private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
 ...
ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
 ...
 }

ContextImpl:

static ContextImpl createActivityContext(ActivityThread mainThread,
            LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
            Configuration overrideConfiguration) {
 ...
 ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
                activityToken, null, 0, classLoader);
...
 final ResourcesManager resourcesManager = ResourcesManager.getInstance();
      //为该context设置对应activity的Resource     
context.setResources(resourcesManager.createBaseActivityResources(activityToken,
                packageInfo.getResDir(),
                splitDirs,
                packageInfo.getOverlayDirs(),
                packageInfo.getApplicationInfo().sharedLibraryFiles,
                displayId,
                overrideConfiguration,
                compatInfo,
                classLoader));
context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,
                context.getResources());
        return context;
 ...
 }

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, ActivityConfigCallback activityConfigCallback) {
            //
        attachBaseContext(context);
        ...
        }

一直super.attachBaseContext(Context base),调度到ContextWrapper.java

// An highlighted block
 protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        //注意这里传进去的时ContextImpl的实例化对象,故调用context的方法时,实际上时调用ContextImpl实现的方法
        mBase = base;
    }

Application Context


在应用冷启动时,会进行Application的实例化。这个文章中我们只关注Application的实例过程中与Contecxt的关系。
废话不多说,上源码!
ActivityThread.java

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
 ...
 	//新建Application, r.packageInfo是LoadedApk的实例
	 Application app = r.packageInfo.makeApplication(false, mInstrumentation);
 ...
 }

再来追追 ,看看makeApplication时候,context有什么幺蛾子。
LoadedApk.java:

  public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
...
			//新建目的Application的Context
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            //实例化Application
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
             //为这个context对象设置OuterContext为该Application对象
            appContext.setOuterContext(app);

...
 }

在Instrumentation.java的newApplication()里面:

    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
...
			Application app = getFactory(context.getPackageName())
                .instantiateApplication(cl, className);
            //在这里将Application与context绑定
        	app.attach(context);
        	return app;

...
 }

Service Context

   private void handleCreateService(CreateServiceData data) {
   ...
   			//实例化Service
			 service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
            //在这里将Service与context绑定,
            //service的Context创建和Application的Context对象都是用同一个方法。
        service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            service.onCreate();

...
 }

BroadcastReceiver Context

 private void handleReceiver(ReceiverData data) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();

        String component = data.intent.getComponent().getClassName();
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);

        IActivityManager mgr = ActivityManager.getService();

        Application app;
        BroadcastReceiver receiver;
        ContextImpl context;
        try {
            app = packageInfo.makeApplication(false, mInstrumentation);
            //直接获取Appplicayion的Context
            context = (ContextImpl) app.getBaseContext();
            ...
            //广播接收器的context是通过onReceive传出的参数
            //这里的传出去的context是Context的子类ReceiverRestrictedContext
            receiver.onReceive(context.getReceiverRestrictedContext(),
                    data.intent);
...
 }

总结


前面可以初略知道代码里面各个组件与context的联系,由前面可以得到一些知识:
1.除了Application外,只有activity和Service继承于Context,且重写了getApplication的方法。所以,可以在activity\service想获取Application对象可以调用getApplication()。但BroadcastReceiver只能调用getBaseContext().getApplicationContext获取所在Application, 而无法使用getApplication。
2.BroadCastReceiver的context 不能调用StartService():因为 在广播接收者中返回的Context实例实际是ReceiverRestrictedContext对象,是继承于ContextWrapper,其重写了StartService(),如下。故不能开启服务。

@Override
    public boolean bindService(Intent service, ServiceConnection conn, int flags) {
        throw new ReceiverCallNotAllowedException(
                "BroadcastReceiver components are not allowed to bind to services");
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值