Context詳解(API29)


Context是一個抽象類,我們通過這個Context可以訪問包內的資源(res和assets)和啓動其他組件(activity、service、broadcast)以及系統服務(systemService)等。所以Context提供了一個應用程序運行環境,在Context的環境裏,應用纔可以訪問資源,才能和其他組件、服務交互,Context定義了一套基本功能接口,我們可以理解爲一套規範,而Activity和Service是實現這套規範的具體實現類(其實內部是ContextImpl統一實現的)。所以可以這樣說,Context是維持Android程序中各個組件能夠正常工作的一個核心功能類。

因爲出於安全的考慮,Android是不允許Activity或者Dialog憑空出現的,一個Activity的啓動必須建立在另一個Activity的基礎之上,也就是以此形成了返回棧。而Dialog則必須在一個Activity上面彈出(如果是系統的除外),因此這種情況下我們只能使用Activity類型的Context。但是(targetSdkVersion >= Build.VERSION_CODES.N && targetSdkVersion < Build.VERSION_CODES.P)是允許的,看api28的源碼。

//ContextImpl.java
 @Override
    public void startActivity(Intent intent, Bundle options) {
        // Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
        // generally not allowed, except if the caller specifies the task id the activity should
        // be launched in. A bug was existed between N and O-MR1 which allowed this to work. We
        // maintain this for backwards compatibility.
        final int targetSdkVersion = getApplicationInfo().targetSdkVersion;

        if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
                && (targetSdkVersion < Build.VERSION_CODES.N
                        || targetSdkVersion >= Build.VERSION_CODES.P)
                && (options == null
                        || ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) {
            throw new AndroidRuntimeException(
                    "Calling startActivity() from outside of an Activity "
                            + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                            + " Is this really what you want?");
        }
        mMainThread.getInstrumentation().execStartActivity(
                getOuterContext(), mMainThread.getApplicationThread(), null,
                (Activity) null, intent, -1, options);
    }

Context實例化

  • Context是個抽象類
  • ContextWrapper是Context的包裝類,內部持有一個Context的引用mBase(ContextImpl類型對象),所有操作都是通過ContextImpl來實現的
  • ContextThemeWrapper與主題theme有關
  • Application(1個context)、Activity/Service(每個對應一個ContextImpl)
  • ContextImpl實例化都是在各自的attach中,傳遞過來的

Activity中的ContextImpl實例化

  • Activity啓動時,通過classLoader加載activity名字,並實例化activity對象。

  • activity繼承自ContextThemeWrapper,ContextThemeWrapper繼承自ContextWrapper,ContextWrapper繼承自Context。

  • 類加載之前需要先加載其父類,類實例化時會先實例化其父類

  • 實例化activity之後,在activity的attach之前,實例化了一個ContextImpl對象。

  • 在activity的attach()方法中,綁定了其父類contextWrapper的contextImpl對象。

//ActivityThread.java
 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ActivityInfo aInfo = r.activityInfo;
        ComponentName component = r.intent.getComponent();
        ContextImpl appContext = createBaseContextForActivity(r); //創建activity的contextImpl實例
        Activity activity = null;

			// classLoader加載實例化activity
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent); 
          
  			// 回調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);

			 // 回調activity的onCreate
             mInstrumentation.callActivityOnCreate(activity, r.state);
           
        return activity;
    }

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

createBaseContextForActivity®; //創建activity的contextImpl實例對象

//ContextImpl.java
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);

		//ResourceManager是個單例對象
        final ResourcesManager resourcesManager = ResourcesManager.getInstance();

        return context;
    }

activity.attach中綁定contextImpl對象

//Activity.java
public class Activity extends ContextThemeWrapper

 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) {
        //綁定ContextWrapper的實現類contextImpl
        attachBaseContext(context);
        //實例化window對象
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    }

 @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase); //回調ContextThemeWrapper方法
    }

ContextThemeWrapper.java

public class ContextThemeWrapper extends ContextWrapper {

 @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase); //回調ContextWrpper方法
    }
}

ContextWrpper.java

public class ContextWrapper extends Context {
    Context mBase; //真正實現功能的類

    protected void attachBaseContext(Context base) {
        mBase = base; //每個activity都會綁定一個ContextImpl對象
    }
 }

在這裏插入圖片描述

Service中的ContextImpl實例化

private void handleCreateService(CreateServiceData data) {
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
         	//通過類加載機制實例化service對象
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);
       		//創建ContextImpl對象
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);

            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService()); //綁定service和contextImpl對象
            service.onCreate();
            mServices.put(data.token, service);
    }

service中創建ContextImpl對象

static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
        return createAppContext(mainThread, packageInfo, null);
    }

    static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo,
            String opPackageName) {
        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
                null, opPackageName);
        context.setResources(packageInfo.getResources());
        return context;
    }

Application中的ContextImpl實例化

  • activityThread.main() ->attach(false) ->ams.attachApplication(mAppThread, startSeq)
  • 在ams中回調mAppThread.bindApplication()
  • mAppThread是ApplicationThread對象,回調其中的bindApplication()
  • sendMessage(H.BIND_APPLICATION, data),給H發送消息
  • 回到主線程,在H(handler)中處理消息,handleBindApplication(data)
  • AppBindData.info.makeApplication()創建application對象並綁定ContextImpl(info是LoadedApk對象)
//LoadedApk.java
public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        Application app = null;

        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }

	        //通過類加載方式實例化application,並綁定ContextImpl
            java.lang.ClassLoader cl = getClassLoader();
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext); 
            appContext.setOuterContext(app);
       
        mActivityThread.mAllApplications.add(app);
        mApplication = app;
		
		//回調callApplicationOnCreate方法
    	instrumentation.callApplicationOnCreate(app); 
        return app;
    }

參考:
Android插件化基礎2----理解Context

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章