以下分别通过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 providers,

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;

List 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 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(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, List pendingResults,

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 HashMap sSharedPrefs =

new HashMap();

/*package*/ LoadedApk mPackageInfo;

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

android context继承关系,android中Context深入详解相关推荐

  1. android context继承关系,Android - 认识Context

    app开发中,我们需要使用app的资源,比如文字.图片,Activity.Service或者broadcastReceiver等等.时常也会用到getApplicationContext()来获取一个 ...

  2. Android 7.1.1 Dialer中通话记录显示详解

    这两天在看通话记录相关问题,顺便跟踪了Dialer中的通话记录是怎么显示出来的,在这和大家分享下.当有来电或去电时,calllog会被插入到calllog.db的数据中去,具体可以参考<Andr ...

  3. Android AVD创建及设置中各参数详解

    本文根据如下的模拟器安装做一些解释: 本文环境:Windows XP sp3,最新JAVa环境,android-sdk_r06-windows.zip,android 2.2 API Level 8, ...

  4. android调webview的方法,Android中的WebView详解

    Android中的WebView详解 WebView详解 基本用法 布局文件配置WebView android:id="@+id/wv_news_detail" android:l ...

  5. Android设置中“强行停止”详解

    Android设置中"强行停止"详解 最近工作上遇到了广播接受不到的问题,查看了<Android 开发艺术探索>一书中关于广播的发送和接受的章节(P356-P362). ...

  6. Android中mesure过程详解 (结合Android 4.0.4 最新源码)

    如何遍历并绘制View树?之前的文章Android中invalidate() 函数详解(结合Android 4.0.4 最新源码)中提到invalidate()最后会发起一个View树遍历的请求,并通 ...

  7. Android中layout过程详解 (结合Android 4.0.4 最新源码)

    上一篇文章Android中mesure过程详解 (结合Android 4.0.4 最新源码)介绍了View树的measure过程,相对与measure过程,本文介绍的layout过程要简单多了,正如l ...

  8. Android 中malloc_debug 原理详解

    版本基于:Android R 关联博文: Android 中malloc_debug 使用详解 0. 前言 最近上项目中遇到一个native 可能内存泄漏的问题,曾考虑使用HWASAN,但这个工具是针 ...

  9. [免费专栏] Android安全之数据存储与数据安全「详解」

    也许每个人出生的时候都以为这世界都是为他一个人而存在的,当他发现自己错的时候,他便开始长大 少走了弯路,也就错过了风景,无论如何,感谢经历 Android安全付费专栏长期更新,本篇最新内容请前往: [ ...

最新文章

  1. 小程序webview不全屏_有赞微信商城和有赞微信小程序什么不一样
  2. OpenCV自适应阈值化函数adaptiveThreshold详解,并附实例源码
  3. rabbitmq 连接过程详解
  4. 文档 笔记 我全都要
  5. 搜狗拼音输入法大头贴新增几个新的模板,欢迎使用.
  6. Azure IoT带来更高效的新能源生产和会看人脸色的无人超市
  7. c语言一个整数各位数字个数_C语言编写程序输出10个整数中最小值或最大值
  8. 职责链模式 Chain of Responsibility
  9. Bean在Spring和SpringMVC中无所不在
  10. 简述 Polkadot 和区块链互联网
  11. 微信小程序的两种视频录制方式
  12. 小米2s刷原生安卓_小米2/2s/2a刷android4.4教程(附2/2s/2a安卓4.4卡刷包下载)
  13. win10 实现远程连接linux系统
  14. HTML吸引人眼球的网页,这8个神奇的HTML5文字特效让你的网页抓人眼球
  15. 小米笔试题 风口的猪-中国牛市
  16. Linux中write函数
  17. vue-quill-editor编辑器踩坑
  18. 韩信点兵(Hanxin)(C++)
  19. 处理IRP的几种方式
  20. MySQL 时间戳操作

热门文章

  1. ustc小道消息20211225
  2. ustc小道消息20211227
  3. 科大星云诗社动态20210925
  4. nova7修屏逛校园2021-07-07
  5. 学长毕业日记 :本科毕业论文写成博士论文的神操作20170404
  6. 窥探黑盒-卷积神经网络的可视化
  7. MFC类中获得其它类指针
  8. 《网络安全——应用技术与工程实践》
  9. 【CyberSecurityLearning 附】Docker 初识
  10. java中删除字符串的头尾空白符。