Activity类组成分析(一)Instrumentation
前言
要了解清楚StartActivity的过程,Activity对象实例的构造过程是重要组成部分;而要弄清楚Activity实例的构造,熟知其重要成员以及设计逻辑是前提,本系列文章主要分析解构Activity类的重要组成成员,以及各成员在Activity的生命周期中扮演什么角色。
解剖
继承关系
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback, WindowControllerCallback,
AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient
可以看到Activity继承ContextThemeWrapper并实现了很多接口,其中包含了我们熟知的onCreateView、onKeyEvent等等。至于context家族的关系暂时不在本文的讨论中了。
重要成员
Instrumentation
这个类写app一般用不到,但是如果写过测试程序肯定有印象,它有强大的跟踪、控制Activity生命周期的能力,一般用在测试框架的基类;之所以这么强大,其实Activity内部关于call生命相关的方法,都是借由Instrumentation类完成的,如startActivity:
* @see #startActivity
*/
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
...
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
...
如app的生命周期方法调用:
final void performResume(boolean followedByPause, String reason) {
dispatchActivityPreResumed();
...
mCalled = false;
// mResumed is set by the instrumentation
mInstrumentation.callActivityOnResume(this);
那么一个app有几个Instrumention实例?是一个Activity拥有一个还是一个app拥有一个?我们来看下它在Activity中如何被赋值的,一步一步寻找答案。
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, IBinder assistToken) {
attachBaseContext(context);
...
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
原来是在attach中被赋值的,那么attach方法是谁调用的?在ActivityThread里。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
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);
...
}
public Instrumentation getInstrumentation()
{
return mInstrumentation;
}
原来mInstrumentation还是ActivityThread的成员变量,我们都知道ActivityThread是一个app有一个实例,那么基本确认所有的Activity都是共享同一个mInstrumentation了。但是这儿还不是创建Instrumentation的地方,继续寻找确定答案。我们找到一个new对象的地方。
private void handleBindApplication(AppBindData data) {
...
} else {
mInstrumentation = new Instrumentation();
}
...
}
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
handleBindApplication在ActivityThread的looper消息循环中的。那么一定有人对ActivityThread的handler发送了BIND_APPLICATION的消息,查找后在BindApplication中印证了
public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) {
...
sendMessage(H.BIND_APPLICATION, data);
}
final ApplicationThread mAppThread = new ApplicationThread();
ApplicationThread是ActivityThread的一个内部类,它继承了ApplicationThreadNative,
public abstract class ApplicationThreadNative extends Binder
implements IApplicationThread {
而ApplicationThreadNative又继承了Binder,所以mAppThread它是一个可以远程调用的对象。那到底是谁调用的bindApplication?其实,在ActivityThread.java这个文件里面是找不到调用它的地方了,其实在ActivityThread的main方法里,进入loop之前调用了一个很重要的方法attach
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
...
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
通过IActivityManager与AMS交互,调用attachApplication方法,同时把mAppThread传过去,想必Ams在做了一些事之后就调用了mAppThread的bindApplication方法吧。去Ams中查看一下。
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
继续看attachApplicationLocked,注意,参数已经是IApplicationThread 了。
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
...
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());
...
}
这样完成了ActivityThread和ams之间的双向交互,是不是有点像回调,只是是通过Binder完成的进程间回调。
这儿有个小疑问,为什么attachApplication方法传递需求的参数类型明明是IApplicationThread,这儿传递的却是ApplicationThread?这是因为ApplicationThread实现了IApplicationThread的接口,当然能够进行参数传递,这是java的知识与binder无关。
整个过程从ActivityThread的main方法到Instrumentation的创建如下图所示。
当app完成进程的创建,就会进入ActivityThread的main方法,这个时候调用attach方法去告诉Ams,我已经创建好啦,同时ams也能得到pid、uid等一些信息,然后回调bind方法通知ActivityThread我已经知道了,我们的关系已经绑定好了,你可以干活了,然后ActivityThread在handleBindApplication中进行Application、Instrumentation等的创建,之后去进行launchActivity的操作,不过这个步骤不在本文的讨论之中。
总结
通过以上叙述我们知道了Instrumentation的建造过程,可以知道一个App只有一个实例,但是他却存在于每一个Activity的生命中。每个Activity都拥有它,但它却不属于任何一个Activity。它就像一个中层管理,老板安排任务,它能直接驱动、监督更底层的打工仔们(各个组件)干活。说这么多,是为了以后看源码的时候遇到它不要害怕,咱知道它就是一个监工就行了。
Activity类组成分析(一)Instrumentation的更多相关文章
- Robotium源码分析之Instrumentation进阶-attach
在分析Robotium的运行原理之前,我们有必要先搞清楚Instrumentation的一些相关知识点,因为Robotium就是基于Instrumentation而开发出来的一套自动化测试框架.鉴于之 ...
- Robotium源码分析之Instrumentation进阶
在分析Robotium的运行原理之前,我们有必要先搞清楚Instrumentation的一些相关知识点,因为Robotium就是基于Instrumentation而开发出来的一套自动化测试框架.鉴于之 ...
- Android群英传》读书笔记 (4) 第八章 Activity和Activity调用栈分析 + 第九章 系统信息与安全机制 + 第十章 性能优化
第八章 Activity和Activity调用栈分析 1.Activity生命周期理解生命周期就是两张图:第一张图是回字型的生命周期图第二张图是金字塔型的生命周期图 注意点(1)从stopped状态重 ...
- Cocos2d-x3.3RC0的Android编译Activity启动流程分析
本文将从引擎源代码Jni分析Cocos2d-x3.3RC0的Android Activity的启动流程,以下是具体分析. 1.引擎源代码Jni.部分Java层和C++层代码分析 watermark/2 ...
- APK包与类更改分析
360APK包与类更改分析 1 题目要求 这是360的全球招募无线攻防中的第二题,题目要求如下: 1)请以重打包的形式将qihootest2.apk的程序包名改为 "com.qihoo.cr ...
- Bot Framework:Activity类简明指南
Bot Framework相关文档:https://docs.botframework.com/en-us/csharp/builder/sdkreference/attachments.html B ...
- MapReduce剖析笔记之八: Map输出数据的处理类MapOutputBuffer分析
在上一节我们分析了Child子进程启动,处理Map.Reduce任务的主要过程,但对于一些细节没有分析,这一节主要对MapOutputBuffer这个关键类进行分析. MapOutputBuffer顾 ...
- android Activity类中的finish()、onDestory()和System.exit(0) 三者的区别
android Activity类中的finish().onDestory()和System.exit(0) 三者的区别 Activity.finish() Call this when your a ...
- Activity类生命周期
Activity通常就是一个单独的屏幕.每一个活动都被实现为一个独立的类,并且从活动基类中继承而来,活动类将会显示由视图控件组成的用户接口,并对事件作出响应. 从开发者角度看,Activity是一个J ...
随机推荐
- 使用SQL-Server分区表功能提高数据库的读写性能
首先祝大家新年快乐,身体健康,万事如意. 一般来说一个系统最先出现瓶颈的点很可能是数据库.比如我们的生产系统并发量很高在跑一段时间后,数据库中某些表的数据量会越来越大.海量的数据会严重影响数据库的读写 ...
- how to updating Node.js and npm
how to updating Node.js and npm 1 Installing Node.js and updating npm How do I update Node.js ? Not ...
- React Hooks: useContext All In One
React Hooks: useContext All In One useContext https://reactjs.org/docs/hooks-reference.html#useconte ...
- VS Code All in One
VS Code All in One Visual Studio Code All in One https://github.com/xgqfrms/vscode/ VS Code Shift + ...
- CSS font-weight all in one
CSS font-weight all in one font-weight: bolder: 没毛病呀! /* 关键字值 */ font-weight: normal; font-weight: b ...
- jest & code testing
jest jest & code testing https://jestjs.io/zh-Hans/ 24.9 https://jestjs.io/docs/zh-Hans/getting- ...
- disable html input & pointer-events
disable html input & pointer-events css https://developer.mozilla.org/en-US/docs/Web/CSS/pointer ...
- lua调用dll导出的函数
参考手册 hello.dll #include "pch.h" #include "lua.hpp" #pragma comment(lib, "lu ...
- NGK官方又出助力市场计划方案 1万枚VAST任性送
近期NGK官方的一系列动作,可以说是在向外界宣告:NGK2.0即将来袭,席卷加密数字货币市场.前一段时间,NGK官方宣布,NGK公链布局算力领域,打造NGK算力生态星空计划,并推出了SPC星空币.目前 ...
- uniapp 自定义弹窗组件
先上效果: 组件源码:slot-modal.vue <template> <view class="modal-container" v-if="sho ...