android中Context深入详解

时间:2022-07-28
本文章向大家介绍android中Context深入详解,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

以下分别通过Context认知角度,继承关系,对象创建等方面android中Context做了深入的解释,一起学习下。

1、Context认知。

Context译为场景,一个应用程序可以认为是一个工作环境,在这个工作环境中可以存在许多场景,coding代码的场景 ,打电话的场景,开会的场景。这些场景可以类比不同的Activity,service。

2、从两个角度认识Context。

第一:Activity继承自Context,同时Activity还实现了其他的interface,我们可以这样看,activity在语法上extends了Context,其本质上是一个Context,但同时其实现了许多interface,扩充了Context的功能,扩充之后的类成为Activity或者Service。

第二:Context本质上包含了场景的所有元素,故而设定其为abstract,Activity和Service继承自Context,它们本质上可以认为就是Context。

3、Context继承关系图

4、Application对象的ContextImpl对象创建过程。

step 1、Ams通过远程Binder调用ActivityThread的内部类ApplicationThread的bingApplication方法,参数包括ApplicationInfo,这个对象由Ams创建,通过IPC传递到ActivityThread的内部类ApplicationThread中。

public final void bindApplication(String processName, 
        ApplicationInfo appInfo, List<ProviderInfo  providers, 
        ComponentName instrumentationName, String profileFile, 
        ParcelFileDescriptor profileFd, boolean autoStopProfiler, 
        Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, 
        int debugMode, boolean isRestrictedBackupMode, boolean persistent, 
        Configuration config, CompatibilityInfo compatInfo, 
        Map<String, IBinder  services, Bundle coreSettings) { 
 
      if (services != null) { 
        // Setup the service cache in the ServiceManager 
        ServiceManager.initServiceCache(services); 
      } 
 
      setCoreSettings(coreSettings); 
 
      AppBindData data = new AppBindData(); 
      data.processName = processName; 
      data.appInfo = appInfo; 
      data.providers = providers; 
      data.instrumentationName = instrumentationName; 
      data.instrumentationArgs = instrumentationArgs; 
      data.instrumentationWatcher = instrumentationWatcher; 
      data.debugMode = debugMode; 
      data.restrictedBackupMode = isRestrictedBackupMode; 
      data.persistent = persistent; 
      data.config = config; 
      data.compatInfo = compatInfo; 
      data.initProfileFile = profileFile; 
      data.initProfileFd = profileFd; 
      data.initAutoStopProfiler = false; 
      queueOrSendMessage(H.BIND_APPLICATION, data); 
    } 

step 2、构建AppBindData对象,如上代码所示。

step 3、调用H Handler,执行handleBindApplication()方法。

static final class AppBindData { 
LoadedApk info; 
String processName; 
ApplicationInfo appInfo; 
List<ProviderInfo  providers; 
ComponentName instrumentationName; 
Bundle instrumentationArgs; 
IInstrumentationWatcher instrumentationWatcher; 
int debugMode; 
boolean restrictedBackupMode; 
boolean persistent; 
Configuration config; 
CompatibilityInfo compatInfo; 
/** Initial values for {@link Profiler}. */ 
String initProfileFile; 
ParcelFileDescriptor initProfileFd; 
boolean initAutoStopProfiler; 
public String toString() { 
return "AppBindData{appInfo=" + appInfo + "}"; 
} 
} 
private void handleBindApplication(AppBindData data) { 
mBoundApplication = data; 
mConfiguration = new Configuration(data.config); 
mCompatConfiguration = new Configuration(data.config); 
//.......... 
TimeZone.setDefault(null); 
/* 
* Initialize the default locale in this process for the reasons we set the time zone. 
*/ 
Locale.setDefault(data.config.locale); 
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);//data.info对象为LoadApk,此时data.info为null,使用getPackageINfoNoCheck创建此对象。 
if (data.instrumentationName != null) {//该条件尽在Android Unit Test工程时会执行到,此处直接看else语句 
ContextImpl appContext = new ContextImpl(); 
appContext.init(data.info, null, this); 
InstrumentationInfo ii = null; 
try { 
ii = appContext.getPackageManager(). 
getInstrumentationInfo(data.instrumentationName, 0); 
} catch (PackageManager.NameNotFoundException e) { 
} 
if (ii == null) { 
throw new RuntimeException( 
"Unable to find instrumentation info for: " 
+ data.instrumentationName); 
} 
mInstrumentationAppDir = ii.sourceDir; 
mInstrumentationAppPackage = ii.packageName; 
mInstrumentedAppDir = data.info.getAppDir(); 
ApplicationInfo instrApp = new ApplicationInfo(); 
instrApp.packageName = ii.packageName; 
instrApp.sourceDir = ii.sourceDir; 
instrApp.publicSourceDir = ii.publicSourceDir; 
instrApp.dataDir = ii.dataDir; 
instrApp.nativeLibraryDir = ii.nativeLibraryDir; 
LoadedApk pi = getPackageInfo(instrApp, data.compatInfo, 
appContext.getClassLoader(), false, true); 
ContextImpl instrContext = new ContextImpl(); 
instrContext.init(pi, null, this); 
try { 
java.lang.ClassLoader cl = instrContext.getClassLoader(); 
mInstrumentation = (Instrumentation) 
cl.loadClass(data.instrumentationName.getClassName()).newInstance(); 
} catch (Exception e) { 
throw new RuntimeException( 
"Unable to instantiate instrumentation " 
+ data.instrumentationName + ": " + e.toString(), e); 
} 
mInstrumentation.init(this, instrContext, appContext, 
new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher); 
if (mProfiler.profileFile != null && !ii.handleProfiling 
&& mProfiler.profileFd == null) { 
mProfiler.handlingProfiling = true; 
File file = new File(mProfiler.profileFile); 
file.getParentFile().mkdirs(); 
Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024); 
} 
try { 
mInstrumentation.onCreate(data.instrumentationArgs); 
} 
catch (Exception e) { 
throw new RuntimeException( 
"Exception thrown in onCreate() of " 
+ data.instrumentationName + ": " + e.toString(), e); 
} 
} else { 
mInstrumentation = new Instrumentation();//初始化Instrumentation对象,一个应用程序对应一个Instrumentation对象 
} 
Application app = data.info.makeApplication(data.restrictedBackupMode, null); 
mInitialApplication = app; 
try { 
mInstrumentation.callApplicationOnCreate(app);//调用Application程序都应的onCreate方法。 
} catch (Exception e) { 
if (!mInstrumentation.onException(app, e)) { 
throw new RuntimeException( 
"Unable to create application " + app.getClass().getName() 
+ ": " + e.toString(), e); 
} 
} 
}

第三步可以又可以分为三小步。

step 3.1、给AppBindData的info变量赋值。

data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);//data.info对象为LoadApk,此时data.info为null,使用getPackageINfoNoCheck创建此对象。

step 3.2、初始化Instrumentation对象。

mInstrumentation = new Instrumentation();//初始化Instrumentation对象,一个应用程序对应一个Instrumentation对象 

step 3.3、创建Application对象。

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

我们着重看一下step 3.1和step3.3.

step 3.1:mPackages和mResourcePackages集合,以packageName为key值,我们知道一个应用程序中的packageName是相同的,也就是说,此处一旦创建,其他地方再次调用此函数,就不需要创建了。总结:也就是说一个应用程序中的LoadedApk对象是唯一的。此处的LoadedApk,也被称为packageInfo。

public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai, 
CompatibilityInfo compatInfo) { 
return getPackageInfo(ai, compatInfo, null, false, true); 
} 
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo, 
ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {/*includeCode 默认为true*/ 
synchronized (mPackages) { 
WeakReference<LoadedApk  ref; 
if (includeCode) {//1、首先从mPackages或者mResourcePackages 集合中以packageName为Key值,获取LoadApk对象。 
ref = mPackages.get(aInfo.packageName); 
} else { 
ref = mResourcePackages.get(aInfo.packageName); 
} 
LoadedApk packageInfo = ref != null ? ref.get() : null; 
if (packageInfo == null || (packageInfo.mResources != null 
&& !packageInfo.mResources.getAssets().isUpToDate())) { 
if (localLOGV) Slog.v(TAG, (includeCode ? "Loading code package " 
: "Loading resource-only package ") + aInfo.packageName 
+ " (in " + (mBoundApplication != null 
? mBoundApplication.processName : null) 
+ ")"); 
packageInfo = 
new LoadedApk(this, aInfo, compatInfo, this, baseLoader, 
securityViolation, includeCode && 
(aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0);//2、如果packageInfo对象为null,则new初始化此对象 
if (includeCode) {//3、最后将创建的此packageInfo对象,加入到mPackages或者mResourcePackages集合中。 
mPackages.put(aInfo.packageName, 
new WeakReference<LoadedApk (packageInfo)); 
} else { 
mResourcePackages.put(aInfo.packageName, 
new WeakReference<LoadedApk (packageInfo)); 
} 
} 
return packageInfo; 
} 
}

step 3.3、总结:每个应用程序都存在一个Application,用户可以在AndroidManifest中重写它,如果不重写也存在一个默认的Application对象。

framework/base/core/java/android/app/LoadedApk.java

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";//1、每个工程都存在一个Application对象,默认的Application对象为android.app.Application,客户端可以重写 
} 
try { 
java.lang.ClassLoader cl = getClassLoader(); 
ContextImpl appContext = new ContextImpl();//2、创建ContextImpl对象,这才是Context的实际实现类 
appContext.init(this, null, mActivityThread);//3、执行ContextImpl对象的init方法,initResource等对象 
app = mActivityThread.mInstrumentation.newApplication(//4、以appContext为参数得到Application对象。 
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);//5、将创建的Application对象,加入到A来了Application中。 
mApplication = app; 
if (instrumentation != null) {//6、此时的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); 
} 
} 
} 
return app; 
}

5、Activity中Context的创建过程

step 1、Ams通过远程Binder调用ActivityThread的Application的scheduleLaunchActivity方法,参数包括ActivityInfo,这个对象由Ams创建,通过IPC传递到ActivityThread的内部类ApplicationThread中。

public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, 
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo, 
Bundle state, List<ResultInfo  pendingResults, 
List<Intent  pendingNewIntents, boolean notResumed, boolean isForward, 
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) { 
ActivityClientRecord r = new ActivityClientRecord(); 
r.token = token; 
r.ident = ident; 
r.intent = intent; 
r.activityInfo = info; 
r.compatInfo = compatInfo; 
r.state = state; 
r.pendingResults = pendingResults; 
r.pendingIntents = pendingNewIntents; 
r.startsNotResumed = notResumed; 
r.isForward = isForward; 
r.profileFile = profileName; 
r.profileFd = profileFd; 
r.autoStopProfiler = autoStopProfiler; 
updatePendingConfiguration(curConfig); 
queueOrSendMessage(H.LAUNCH_ACTIVITY, r); 
}

step 2、构建ActivityClientRecord对象,如上代码所示。

step 3、调用H Handler,执行handleLaunchActivity()方法。

其中step 3,又可分为10小步。

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { 
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")"); 
ActivityInfo aInfo = r.activityInfo; 
if (r.packageInfo == null) {//1、如果packageInfo为null,则调用getPackageInfo的得到LoadedApk 
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 = null; 
try {//2、调用mInstrumentation的newActivity方法,得到Activity对象 
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) { 
if (!mInstrumentation.onException(activity, e)) { 
throw new RuntimeException( 
"Unable to instantiate activity " + component 
+ ": " + e.toString(), e); 
} 
} 
try { 
Application app = r.packageInfo.makeApplication(false, mInstrumentation);//3、获取Application对象 
if (localLOGV) Slog.v(TAG, "Performing launch of " + r); 
if (localLOGV) Slog.v( 
TAG, r + ": app=" + app 
+ ", appName=" + app.getPackageName() 
+ ", pkg=" + r.packageInfo.getPackageName() 
+ ", comp=" + r.intent.getComponent().toShortString() 
+ ", dir=" + r.packageInfo.getAppDir()); 
if (activity != null) {//4、创建ContextImpl对象 
ContextImpl appContext = new ContextImpl(); 
appContext.init(r.packageInfo, r.token, this); 
appContext.setOuterContext(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);//5、执行Activity的attach方法,将此ContextImpl对象,设置给Activity,activity会调用attachBaseContext 
if (customIntent != null) { 
activity.mIntent = customIntent; 
} 
r.lastNonConfigurationInstances = null; 
activity.mStartedActivity = false; 
int theme = r.activityInfo.getThemeResource();//6、设置主题 
if (theme != 0) { 
activity.setTheme(theme); 
} 
activity.mCalled = false; 
mInstrumentation.callActivityOnCreate(activity, r.state);//7、执行Activity的onCreate方法 
if (!activity.mCalled) { 
throw new SuperNotCalledException( 
"Activity " + r.intent.getComponent().toShortString() + 
" did not call through to super.onCreate()"); 
} 
r.activity = activity; 
r.stopped = true; 
if (!r.activity.mFinished) { 
activity.performStart();//8、执行Activity的onStart方法 
r.stopped = false; 
} 
if (!r.activity.mFinished) { 
if (r.state != null) { 
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);//9、质细腻感onRestoresInstanceState方法 
} 
} 
if (!r.activity.mFinished) { 
activity.mCalled = false; 
mInstrumentation.callActivityOnPostCreate(activity, r.state); 
if (!activity.mCalled) { 
throw new SuperNotCalledException( 
"Activity " + r.intent.getComponent().toShortString() + 
" did not call through to super.onPostCreate()"); 
} 
} 
} 
r.paused = true; 
mActivities.put(r.token, r);//10、将包含activity信息集的r对象,也就是ActivityClientRecord,加入到mActivities中,r.token为key值。 
} catch (SuperNotCalledException e) { 
throw e; 
} catch (Exception e) { 
if (!mInstrumentation.onException(activity, e)) { 
throw new RuntimeException( 
"Unable to start activity " + component 
+ ": " + e.toString(), e); 
} 
} 
return activity; 
}

总结:activity的packageInfo对象和application的packageInfo是同一个对象。

6、Service中Context的创建过程

step 1、Ams通过远程Binder调用ActivityThread的内部类ApplicationThread的scheduleCreateService方法,参数包括serviceInfo,这个对象由Ams创建,通过IPC传递到ActivityThread的内部类ApplicationThread中。

public final void scheduleCreateService(IBinder token, 
ServiceInfo info, CompatibilityInfo compatInfo) { 
CreateServiceData s = new CreateServiceData(); 
s.token = token; 
s.info = info; 
s.compatInfo = compatInfo; 
queueOrSendMessage(H.CREATE_SERVICE, s); 
}

step 2、构建CreateServiceData对象,如上代码所示。

step 3、调用H Handler,执行handleCreateService()方法。

其中step 3又可分为一下5步。

private void handleCreateService(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);//1、得到packageInfo,调用getPackageInfoNoCheck 
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)) { 
throw new RuntimeException( 
"Unable to instantiate service " + data.info.name 
+ ": " + e.toString(), e); 
} 
} 
try { 
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name); 
ContextImpl context = new ContextImpl();//2、创建ContextImpl对象 
context.init(packageInfo, null, this); 
Application app = packageInfo.makeApplication(false, mInstrumentation);//3、得到Application对象 
context.setOuterContext(service); 
service.attach(context, this, data.info.name, data.token, app, 
ActivityManagerNative.getDefault());//4、调用service的attach方法,将实例化的ContextImpl设置给Service 
service.onCreate(); 
mServices.put(data.token, service);//5、将service对象加入到mService集合中,key值为data.token。 
try { 
ActivityManagerNative.getDefault().serviceDoneExecuting( 
data.token, 0, 0, 0); 
} catch (RemoteException e) { 
// nothing to do. 
} 
} catch (Exception e) { 
if (!mInstrumentation.onException(service, e)) { 
throw new RuntimeException( 
"Unable to create service " + data.info.name 
+ ": " + e.toString(), e); 
} 
} 
}

综上所述:

1、无论是Application还是Activity、Service,他们的LoadedApk对象都是同一个,或者说packageInfo为同一个对象。

2、在创建ContextImpl对象时,Application和SErvice通过getPackageInfoNoCheck方法,Activity通过getPackageInfo方法得到。

3、一个应用程序中Context的个数 = Activity的数量+Service的数量 +1。这里的1代表Application。

4、应用程序中包含着多个ContextImpl对象,其内部的PackageInfo却是同一个。这样设计意味着ContextImpl是一个轻量级类,PackageInfo是一个重量级类,所有和包相关的操作封装到PackageInfo中,有利于代码的封装与隐藏。

class ContextImpl extends Context { 
private final static String TAG = "ApplicationContext"; 
private final static boolean DEBUG = false; 
private static final HashMap<String, SharedPreferencesImpl  sSharedPrefs = 
new HashMap<String, SharedPreferencesImpl (); 
/*package*/ LoadedApk mPackageInfo;

以上就是本篇文章的全部内容,希望大家通过学习能够对Context有更深入的理解。