Activity类组成分析(一)Instrumentation

目录
  • 前言
  • 解剖
    • 继承关系
    • 重要成员
      • Instrumentation
  • 总结

前言

技术资讯 https://www.yehe.org/

要了解清楚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。它就像一个中层管理,老板安排任务,它能直接驱动、监督更底层的打工仔们(各个组件)干活。说这么多,是为了以后看源码的时候遇到它不要害怕,咱知道它就是一个监工就行了。

猜你喜欢

转载自blog.csdn.net/nidongla/article/details/115223067