今天就跟大家聊聊有关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, Listproviders, ComponentName instrumentationName, String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, int debugMode, boolean isRestrictedBackupMode, boolean persistent, Configuration config, CompatibilityInfo compatInfo, Map 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; Listproviders; 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) { WeakReferenceref; 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 (packageInfo)); } else { mResourcePackages.put(aInfo.packageName, new WeakReference (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, ListpendingResults, List 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 HashMapsSharedPrefs = new HashMap (); /*package*/ LoadedApk mPackageInfo;
看完上述内容,你们对android中Context有什么用有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注创新互联行业资讯频道,感谢大家的支持。