Android之Context理解

context,一直以来,即是我熟悉又陌生的东西。我知道一个app的context数量=activity+service+application,也知道各种context的作用范围,却依然似懂非懂。今天,根据源码和自己的理解,简单梳理下,以作备忘。

何为Context?

context意为上下文、环境。我个人认为所处的上下文即所处的环境,也就是某对象所处的环境。我个人习惯比喻为:如果有一个大鱼缸,里面装满了水和鱼。那么,对于鱼来说,它的context,即所处的环境,也就是水了,对应着 view和其所在的activity;而对于水来来说,其所处环境就是鱼缸,对应着在一个进程里面各个部件所处的整体context就是application,它是一个大环境。

Context的种类和作用范围

  • getApplication()获得的context的全局单例application,这和getApplicationContext()获取的context其实是同一个,唯一的区别是前者只能在activity和service中使用,后者在Brocast中也可以用来获取context。
  • activity和service本身也是一个context,view的getContext()获取的是activity,具体使用那个context,要视具体场景。比如,activity弹出的dialog只能是activity,启动一个activity最好用启动他的context,具体的可以google,本文重点不在于此。

Context的结构模式

Context使用了装饰者设计模式。简单来说,装饰者模式Decorator的目的是为了给一个类(对象)动态添加额外的职责(动态扩展对象的功能)。比如说我们有一个抽象类Component,有一个具体实现类ConcertCompent,但是我们的需求的一般情况下直接用ConcertCompent,有时候需要这个对象能有其他的功能但又不能写死他。这时候就需要“动态扩展”了。

可以构造一个(抽象)类Decorator,继承自Component和持有ConcertComponent的引用,然后在他的重写方法里面调用ConcertComponent的方法,这样做的好处是可以让不同子类继承他实现不同功能的扩展,也就完成了对被装饰者(引用)的扩展。

Decorator设计模式UML图如下:

Android中Context的结构图

显而易见是运用了该设计模式,我们来追踪一下。

Context追踪

前提回顾: 一般而言,启动进程的顺序大致如下:

  • 如果是冷启动,Launch的startActivity或者其他界面发起的startActivity,首先系统先判断是否存在该进程,不存在则fork一个进程。
  • 然后调用ActivityThread的main方法,实例化ActivityThread,实例化Looper,通过ActivityThread的attach方法的Binder IPC机制将ApplicationThread交付AMS,然后开启消息循环。
  • 然后AMS调用startActivity->scheduleLaunchActiivty->H.sendMessage->主线程的handleLaunchActivity->performLaunchActivity,我们重点关注“performLaunchActivity”
  • 热启动的话launch直接向AMS发起请求,重复以上步骤。

performLaunchActiivty所做的大致是,加载组件信息实例化activity,实例化Application,实例化ContextImp并完成activityc初始化,调用onCreate,onStart,onRestoreInstance等。其中,ContextImp一般应该没有被算在多少个context里面,我不太清楚,计算这个也没什么意义。

Activity实例化

加载组件信息

ActivityInfo aInfo = r.activityInfo;    if (r.packageInfo == null) {    r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,            Context.CONTEXT_INCLUDE_CODE);    }    ComponentName component = r.intent.getComponent();    if (component == null) {    component = r.intent.resolveActivity(        mInitialApplication.getPackageManager());    r.intent.setComponent(component);    }    if (r.activityInfo.targetActivity != null) {    component = new ComponentName(r.activityInfo.packageName,            r.activityInfo.targetActivity);    }

实例化Activity

 Activity activity = null;    try {    java.lang.ClassLoader cl = r.packageInfo.getClassLoader();    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);    }    } catch (Exception e) {    if (!mInstrumentation.onException(activity, e)) {        throw new RuntimeException(            "Unable to instantiate activity " + component            + ": " + e.toString(), e);    }    }

Application实例化

  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();        if (!mPackageName.equals("android")) {            initializeJavaContextClassLoader();        }        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);        app = mActivityThread.mInstrumentation.newApplication(                cl, appClass, appContext);        appContext.setOuterContext(app);    } catch (Exception e) {        if (!mActivityThread.mInstrumentation.onException(app, e)) {            throw new RuntimeException(                "Unable to instantiate application " + appClass                + ": " + e.toString(), e);        }    }    mActivityThread.mAllApplications.add(app);    mApplication = app;    if (instrumentation != null) {        try {            instrumentation.callApplicationOnCreate(app);        } catch (Exception e) {            if (!instrumentation.onException(app, e)) {                throw new RuntimeException(                    "Unable to create application " + app.getClass().getName()                    + ": " + e.toString(), e);            }        }    }    // Rewrite the R 'constants' for all library apks.    SparseArray packageIdentifiers = getAssets(mActivityThread)            .getAssignedPackageIdentifiers();    final int N = packageIdentifiers.size();    for (int i = 0; i < N; i++) {        final int id = packageIdentifiers.keyAt(i);        if (id == 0x01 || id == 0x7f) {            continue;        }        rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);    }    return app;    }

ContextImp实例化,每个contextimp最终都是通过ContextWrapper的attachBaseContext附加上去的

 Context appContext = createBaseContextForActivity(r, activity);    CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());    Configuration config = new Configuration(mCompatConfiguration);    if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "        + r.activityInfo.name + " with config " + config);    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);

初始化activity

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) {    attachBaseContext(context);    mFragments.attachHost(null /*parent*/);    mWindow = new PhoneWindow(this);    mWindow.setCallback(this);    mWindow.setOnWindowDismissedCallback(this);    mWindow.getLayoutInflater().setPrivateFactory(this);    if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {        mWindow.setSoftInputMode(info.softInputMode);    }    if (info.uiOptions != 0) {        mWindow.setUiOptions(info.uiOptions);    }    mUiThread = Thread.currentThread();    mMainThread = aThread;    mInstrumentation = instr;    mToken = token;    mIdent = ident;    mApplication = application;    mIntent = intent;    mReferrer = referrer;    mComponent = intent.getComponent();    mActivityInfo = info;    mTitle = title;    mParent = parent;    mEmbeddedID = id;    mLastNonConfigurationInstances = lastNonConfigurationInstances;    if (voiceInteractor != null) {        if (lastNonConfigurationInstances != null) {            mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;        } else {            mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,                    Looper.myLooper());        }    }    mWindow.setWindowManager(            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),            mToken, mComponent.flattenToString(),            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);    if (mParent != null) {        mWindow.setContainer(mParent.getWindow());    }    mWindowManager = mWindow.getWindowManager();    mCurrentConfig = config;    }

更多相关文章

  1. android四大组件-Activity
  2. 关于android中activity的四种启动模式
  3. Android(安卓)JNI小实例
  4. android使程序进程不被LMK杀死| application运行环境初始化
  5. Android位置服务--BaiduMap的使用(2)
  6. IPC多进程模式学习笔记
  7. Android(安卓)NDK安装
  8. 搭建Android手机系统开发环境
  9. 结合Android浅谈Builder模式

随机推荐

  1. Android中TextView和EditView常用属性设
  2. Android(安卓)图片放大缩小
  3. 转:大厂Android面试题
  4. 教你瘦身zxing(android)
  5. 开箱即用!Android四款系统架构工具
  6. Android对不同DPI的dimen选择优先级问题
  7. Android AIDL服务学习笔记
  8. 福利来了!带你“爱上Android”
  9. selector背景以及android的透明色
  10. Android启动过程以及各个镜像的关系