天天看點

android tag的作用,Android中的Context的作用(2)

ContextImpl關鍵成員和函數

classContextImplextendsContext {

privatefinalstaticString TAG ="ContextImpl";

privatefinalstaticbooleanDEBUG =false;

privatestaticfinalHashMap sSharedPrefs =

newHashMap();

LoadedApk mPackageInfo;// 關鍵資料成員

privateString mBasePackageName;

privateResources mResources;

ActivityThread mMainThread;// 主線程

@Override

publicAssetManager getAssets() {

returngetResources().getAssets();

}

@Override

publicLooper getMainLooper() {

returnmMainThread.getLooper();

}

@Override

publicObject getSystemService(String name) {

ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);

returnfetcher ==null?null: fetcher.getService(this);

}

@Override

publicvoidstartActivity(Intent intent, Bundle options) {

warnIfCallingFromSystemProcess();

if((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) ==0) {

thrownewAndroidRuntimeException(

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

}

}

ContextWrapper

它隻是對Context類的一種封裝,它的構造函數包含了一個真正的Context引用,即ContextImpl對象。

publicclassContextWrapperextendsContext {

Context mBase; //該屬性指向一個ContextIml執行個體

publicContextWrapper(Context base) {

mBase = base;

}

protectedvoidattachBaseContext(Context base) {

if(mBase !=null) {

thrownewIllegalStateException("Base context already set");

}

mBase = base;

}

@Override

publicLooper getMainLooper() {

returnmBase.getMainLooper();

}

@Override

publicObject getSystemService(String name) {

returnmBase.getSystemService(name);

}

@Override

publicvoidstartActivity(Intent intent) {

mBase.startActivity(intent);

}

}

ContextThemeWrapper

該類内部包含了主題(Theme)相關的接口,即android:theme屬性指定的。隻有Activity需要主題,Service不需要主題,是以Service直接繼承于ContextWrapper類。

publicclassContextThemeWrapperextendsContextWrapper {

privateContext mBase;

privateintmThemeResource;

privateResources.Theme mTheme;

privateLayoutInflater mInflater;

privateConfiguration mOverrideConfiguration;

privateResources mResources;

publicContextThemeWrapper() {

super(null);

}

publicContextThemeWrapper(Context base,intthemeres) {

super(base);

mBase = base;

mThemeResource = themeres;

}

@OverrideprotectedvoidattachBaseContext(Context newBase) {

super.attachBaseContext(newBase);

mBase = newBase;

}

@OverridepublicvoidsetTheme(intresid) {

mThemeResource = resid;

initializeTheme();

}

@OverridepublicResources.Theme getTheme() {

if(mTheme !=null) {

returnmTheme;

}

mThemeResource = Resources.selectDefaultTheme(mThemeResource,

getApplicationInfo().targetSdkVersion);

initializeTheme();

returnmTheme;

}

}

何時建立Context

應用程式在以下幾種情況下建立Context執行個體:

1) 建立Application 對象時, 而且整個App共一個Application對象

2) 建立Service對象時

3) 建立Activity對象時

是以應用程式App共有的Context數目公式為:

總Context執行個體個數 = Service個數 + Activity個數 + 1(Application對應的Context執行個體)

ActivityThread消息處理函數與本節相關的内容如下:

publicvoidhandleMessage(Message msg) {

if(DEBUG_MESSAGES) Slog.v(TAG,">>> handling: "+ codeToString(msg.what));

switch(msg.what) {

caseLAUNCH_ACTIVITY: {// 建立Activity對象

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");

ActivityClientRecord r = (ActivityClientRecord)msg.obj;

r.packageInfo = getPackageInfoNoCheck(

r.activityInfo.applicationInfo, r.compatInfo);

handleLaunchActivity(r, null);

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

} break;

caseBIND_APPLICATION:// 建立Application對象

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");

AppBindData data = (AppBindData)msg.obj;

handleBindApplication(data);

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

break;

caseCREATE_SERVICE:// 建立Service對象

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");

handleCreateService((CreateServiceData)msg.obj);

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

break;

caseBIND_SERVICE:// Bind Service對象

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");

handleBindService((BindServiceData)msg.obj);

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

break;

}

}

建立Application對象時建立Context執行個體

每個應用程式在第一次啟動時,都會首先建立一個Application對象。從startActivity流程可知,建立Application的時機在handleBindApplication()方法中,該函數位于 ActivityThread.java類中 ,相關代碼如下:

// ActivityThread.java

privatevoidhandleBindApplication(AppBindData data) {

try{

// If the app is being launched for full backup or restore, bring it up in

// a restricted environment with the base application class.

Application app = data.info.makeApplication(data.restrictedBackupMode, null);

mInitialApplication = app;

...

} finally{

StrictMode.setThreadPolicy(savedPolicy);

}

}

// LoadedApk.java

publicApplication makeApplication(booleanforceDefaultAppClass,

Instrumentation instrumentation) {

if(mApplication !=null) {

returnmApplication;

}

Application app = null;

String appClass = mApplicationInfo.className;

if(forceDefaultAppClass || (appClass ==null)) {

appClass = "android.app.Application";

}

try{

java.lang.ClassLoader cl = getClassLoader();

ContextImpl appContext = newContextImpl();// 建立ContextImpl執行個體

appContext.init(this,null, mActivityThread);

app = mActivityThread.mInstrumentation.newApplication(

cl, appClass, appContext);

appContext.setOuterContext(app); // 将Application執行個體傳遞給Context執行個體

} catch(Exception e) {

...

}

mActivityThread.mAllApplications.add(app);

mApplication = app;

returnapp;

}

建立Activity對象時建立Context執行個體

通過startActivity()或startActivityForResult()請求啟動一個Activity時,如果系統檢測需要建立一個Activity對象時,就會回調handleLaunchActivity()方法,該方法繼而調用performLaunchActivity()方法,去建立一個Activity執行個體,并且回調onCreate(),onStart()方法等,函數都位于 ActivityThread.java類 ,相關代碼如下:

privatevoidhandleLaunchActivity(ActivityClientRecord r, Intent customIntent) {

...

Activity a = performLaunchActivity(r, customIntent); // 到下一步

if(a !=null) {

r.createdConfig = newConfiguration(mConfiguration);

Bundle oldState = r.state;

handleResumeActivity(r.token, false, r.isForward,

!r.activity.mFinished && !r.startsNotResumed);

...

}

...

}

privateActivity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

...

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

if(r.state !=null) {

r.state.setClassLoader(cl);

}

} catch(Exception e) {

...

}

try{

Application app = r.packageInfo.makeApplication(false, mInstrumentation);

if(activity !=null) {

Context appContext = createBaseContextForActivity(r, activity); // 建立Context

CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());

Configuration config = newConfiguration(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);

if(customIntent !=null) {

activity.mIntent = customIntent;

}

r.lastNonConfigurationInstances = null;

activity.mStartedActivity = false;

inttheme = r.activityInfo.getThemeResource();

if(theme !=0) {

activity.setTheme(theme);

}

mActivities.put(r.token, r);

} catch(SuperNotCalledException e) {

...

} catch(Exception e) {

...

}

returnactivity;

}

privateContext createBaseContextForActivity(ActivityClientRecord r,

finalActivity activity) {

ContextImpl appContext = newContextImpl();// 建立ContextImpl執行個體

appContext.init(r.packageInfo, r.token, this);

appContext.setOuterContext(activity);

// For debugging purposes, if the activity's package name contains the value of

// the "debug.use-second-display" system property as a substring, then show

// its content on a secondary display if there is one.

Context baseContext = appContext;

String pkgName = SystemProperties.get("debug.second-display.pkg");

if(pkgName !=null&& !pkgName.isEmpty()

&& r.packageInfo.mPackageName.contains(pkgName)) {

DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();

for(intdisplayId : dm.getDisplayIds()) {

if(displayId != Display.DEFAULT_DISPLAY) {

Display display = dm.getRealDisplay(displayId);

baseContext = appContext.createDisplayContext(display);

break;

}

}

}

returnbaseContext;

}

建立Service對象時建立Context執行個體

通過startService或者bindService時,如果系統檢測到需要新建立一個Service執行個體,就會回調handleCreateService()方法,完成相關資料操作。handleCreateService()函數位于 ActivityThread.java類,如下:

privatevoidhandleCreateService(CreateServiceData data) {

// If we are getting ready to gc after going to the background, well

// we are back active so skip it.

unscheduleGcIdler();

LoadedApk packageInfo = getPackageInfoNoCheck(

data.info.applicationInfo, data.compatInfo);

Service service = null;

try{

java.lang.ClassLoader cl = packageInfo.getClassLoader();

service = (Service) cl.loadClass(data.info.name).newInstance();

} catch(Exception e) {

if(!mInstrumentation.onException(service, e)) {

thrownewRuntimeException(

"Unable to instantiate service "+ data.info.name

+ ": "+ e.toString(), e);

}

}

try{

if(localLOGV) Slog.v(TAG,"Creating service "+ data.info.name);

ContextImpl context = newContextImpl();// 建立ContextImpl執行個體

context.init(packageInfo, null,this);

Application app = packageInfo.makeApplication(false, mInstrumentation);

context.setOuterContext(service);

service.attach(context, this, data.info.name, data.token, app,

ActivityManagerNative.getDefault());

service.onCreate();

mServices.put(data.token, service);

try{

ActivityManagerNative.getDefault().serviceDoneExecuting(

data.token, 0,0,0);

} catch(RemoteException e) {

// nothing to do.

}

} catch(Exception e) {

if(!mInstrumentation.onException(service, e)) {

thrownewRuntimeException(

"Unable to create service "+ data.info.name

+ ": "+ e.toString(), e);

}

}

}

小結

通過對ContextImp的分析可知,其方法的大多數操作都是直接調用其屬性mPackageInfo(該屬性類型為PackageInfo)的相關方法而來。這說明ContextImp是一種輕量級類,而PackageInfo才是真正重量級的類。而一個App裡的所有ContextImpl執行個體,都對應同一個packageInfo對象。

【責任編輯:chenqingxiang TEL:(010)68476606】