美文网首页
Activity从启动到绘制

Activity从启动到绘制

作者: 总是一点点 | 来源:发表于2019-11-26 19:00 被阅读0次

    果然人在家里就比较容易犯懒,差点又被自己说服去睡觉了。——10.2
    被ActivityTaskManagerService玩惨了——10.3

    前言

    前面已经梳理了一下,我们的布局文件layout是如何加载的,原材料已经有了,现在就可以总结一下我们耳熟能详的measurelayoutdraw了。
    结果今天看了两篇博客之后,发现事情并没有这么简单,好像少了点什么??
    嗯...我们把整个事情的整个流程捋一下:
    首先,我们把自定义layout加载到DecorView
    然后,我们按照measurelayoutdraw流程来绘制View......
    嗯...
    不对啊!DecorView是在哪显示的,又是在哪调用的绘制View......
    ......
    我的Activity呢???我的Window呢??我这么大一个组件怎么就没了?!

    我哭了

    所以,只能含着泪在标题上加上了“前一章”的字样(看来不能好好睡觉了),只能先来看看:

    • Activity的启动过程;
    • ActivityWindow又是怎么来衔接DecorView的加载和绘制的;

    源码

    Activity启动分析

    回归到一个刚刚接触到Android的萌新状态(虽然现在也是萌新),如果说需要显示或者说修改UI,第一件事就是打开Activity。众所周知,Activity是一种用于直接向用户展示界面的组件。OK,那我们从Activity开始入手,一步一步看一下他是如何展示界面的。

        Intent intent = new Intent(this, TestActivity.class);
        startActivity(intent);
    

    这就是我们可以见到的Activity的起点,代码非常简单,直接调用Activity.startActivity()
    继续向下看startActivity()经过几次重载,最终调用了startActivityForResult()

        public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
                @Nullable Bundle options) {
            if (mParent == null) {
                //1.对options进行封装,options为null就采用系统默认,不为空则直接使用
                options = transferSpringboardActivityOptions(options);
                //2.生成ActivityResult对象,里面包含resultCode和resultData
                Instrumentation.ActivityResult ar =
                    mInstrumentation.execStartActivity(
                        this, mMainThread.getApplicationThread(), mToken, this,
                        intent, requestCode, options);
                //3.执行发送消息ActivityResult
                if (ar != null) {
                    mMainThread.sendActivityResult(
                        mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                        ar.getResultData());
                }
                if (requestCode >= 0) {
                    mStartedActivity = true;
                }
                //取消输入功能和动画的执行
                cancelInputsAndStartExitTransition(options);
                // TODO Consider clearing/flushing other event sources and events for child windows.
            } else {
                //通过mParent创建,创建过程与上方代码类似
            }
        }
    

    看了一下刚哥的《开发艺术探索》这里的mParent是用来针对镶嵌子Activity的场景的,这里只需要看mParent == null.(正好我们只是想看一下启动和绘制的关系,这里就不纠结了),大致流程如下:

    1. options进行封装,optionsnull就采用系统默认,不为null则直接使用;
    2. 生成ActivityResult对象,里面包含resultCoderesultData;
    3. 执行发送消息ActivityResult;
    4. 取消输入功能和动画的执行;
      这里可以看到在第三步中已经开始发送ActivityResult,那Activity的启动应该就在第二步中的Instrumentation.execStartActivity(),我们跟进去看代码;
        public ActivityResult execStartActivity(
                Context who, IBinder contextThread, IBinder token, Activity target,
                Intent intent, int requestCode, Bundle options) {
            IApplicationThread whoThread = (IApplicationThread) contextThread;
            //1.存储`startActivity()`发起者的信息
            Uri referrer = target != null ? target.onProvideReferrer() : null;
            if (referrer != null) {
                intent.putExtra(Intent.EXTRA_REFERRER, referrer);
            }
            //2.测试相关判定
            if (mActivityMonitors != null) {
                //ActivityMonitor类是Google为了InstrumentationTest而加入的一个工具类,这里不关注
            }
            try {
                intent.migrateExtraStreamToClipData();
                intent.prepareToLeaveProcess(who);
                //3.启动Activity的核心
                int result = ActivityTaskManager.getService()
                    .startActivity(whoThread, who.getBasePackageName(), intent,
                            intent.resolveTypeIfNeeded(who.getContentResolver()),
                            token, target != null ? target.mEmbeddedID : null,
                            requestCode, 0, null, options);
                //4.用于检查打开Activity异常的方法,我们常见的Activity启动异常都在这里
                checkStartActivityResult(result, intent);
            } catch (RemoteException e) {
                throw new RuntimeException("Failure from system", e);
            }
            return null;
        }
    

    大致流程如下:

    1. .存储startActivity()发起者的信息;
    2. 测试相关判定;
    3. 启动Activity的核心;
    4. 用于检查打开Activity异常的方法,我们常见的Activity启动异常都在这里;

    说实话,看到这里,我多少是有点小激动的,毕竟看起来,马上就可以揭晓谜底了,但是现实告诉我:"你高兴的太早了!",点进去看一下启动Activity的核心:

        public static IActivityTaskManager getService() {
            return IActivityTaskManagerSingleton.get();
        }
    
        @UnsupportedAppUsage(trackingBug = 129726065)
        private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
                new Singleton<IActivityTaskManager>() {
                    @Override
                    protected IActivityTaskManager create() {
                        final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
                        return IActivityTaskManager.Stub.asInterface(b);
                    }
                };
    

    直接看代码的最后一行,出现了关键句IActivityTaskManager.Stub.asInterface(b)这里使用Binder的进程间通信,但是IActivityTaskManager是什么东西?,不应该是IActivityManager吗?然后转到ActivityManagerService中?我太难了!!!
    但是,不能气馁,我们先看一下ActivityManagerService的代码,虽然代码有变化,但是基本结构应该不会有非常大的变化。
    于是我找到了这个:

        public ActivityTaskManagerService mActivityTaskManager;
    

    看一下ActivityTaskManagerService的源码:

        public class ActivityTaskManagerService extends IActivityTaskManager.Stub
    

    哈哈,功夫不负有心人,应该就是这里了,我们找一下startActivity()

        public final int startActivity(IApplicationThread caller, String callingPackage,
                Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
                int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
            return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                    resultWho, requestCode, startFlags, profilerInfo, bOptions,
                    UserHandle.getCallingUserId());
        }
    

    之后就开始了N多的跳转最终来到了ClientLifecycleManager.class,在这里通过ClientTransaction.classClientTransactionItem对Activity的加载和生命周期进行控制,这里只是加载,看代码:

                    // Create activity launch transaction.
                    final ClientTransaction clientTransaction = ClientTransaction.obtain(
                            proc.getThread(), r.appToken);
    
                    final DisplayContent dc = r.getDisplay().mDisplayContent;
                    clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                            System.identityHashCode(r), r.info,
                            // TODO: Have this take the merged configuration instead of separate global
                            // and override configs.
                            mergedConfiguration.getGlobalConfiguration(),
                            mergedConfiguration.getOverrideConfiguration(), r.compat,
                            r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
                            r.icicle, r.persistentState, results, newIntents,
                            dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
                                    r.assistToken));
    
                    // Set desired final state.
                    final ActivityLifecycleItem lifecycleItem;
                    if (andResume) {
                        lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
                    } else {
                        lifecycleItem = PauseActivityItem.obtain();
                    }
                    clientTransaction.setLifecycleStateRequest(lifecycleItem);
    

    这里关键是使用了LaunchActivityItemResumeActivityItem(也有用PauseActivityItem)分布对应Activity中对应的生命周期:onCreate()onResume,onPause
    然后通过ActivityThreadApplicationThreadHActivity进行控制,调用ActivityThread中的handleLaunchActivityhandleResumeActivity,具体流程如图:

    画到吐血的流程图

    DecorView绘制的调用

    上面Activity启动的流程图的最后一步(第50步)没有仔细的绘制,接下来的部分会对这一部分进行详解,这里也就是DecorView绘制的调用。
    看代码,这里只保留绘制相关部分:

    <ActivityThread.java>
    
        public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
                String reason) {
                ......
                if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (r.mPreserveWindow) {
                    a.mWindowAdded = true;
                    r.mPreserveWindow = false;
                    ViewRootImpl impl = decor.getViewRootImpl();
                    if (impl != null) {
                        impl.notifyChildRebuilt();
                    }
                }
                if (a.mVisibleFromClient) {
                    if (!a.mWindowAdded) {
                        a.mWindowAdded = true;
                        wm.addView(decor, l);
                    }
                }
                ......
        }
    

    这里通过Activity获取到ViewManager,然后通过 使用ViewManager.addView()WindowView进行关联。
    通过Activity获取到的ViewManager的本质是一个WindowManagerImp,看一下WindowManagerImp.addView()的代码:

    <WindowManagerImp.java>
    
        public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
            applyDefaultToken(params);
            mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
        }
    

    这里并没有进行比较哦多的操作,而是直接调用了mGlobal.addView.(代码部分删减):

        public void addView(View view, ViewGroup.LayoutParams params,
                Display display, Window parentWindow) {
            final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
            ViewRootImpl root;
            View panelParentView = null;
            //创建一个ViewRootImpl对象
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);
            
            // do this last because it fires off messages to start doing things
            root.setView(view, wparams, panelParentView);
        }
    

    这里继续看root.setView(view, wparams, panelParentView),进入到了ViewRootImpl,这里也是主要的View绘制过程的调用,经过几次调用,最终:

    <ViewRootImpl.java>
    
          mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
          mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    

    在主线程中,使用TraversalRunnable开始绘制,整体流程如下:

    UI绘制的调用

    总结
    1.Android Q 中Activity的启动,不再使用ActivityManagerService,替换为ActivityTaskManagerService;
    2.UI在onCreate中进行自定义布局的设置,在handleResumeActivity完成UI绘制;
    3.Window 与 WindowManager 之间的桥接模式,依赖关系存在于抽象类间,与实现&行为完全隔离

    相关文章

      网友评论

          本文标题:Activity从启动到绘制

          本文链接:https://www.haomeiwen.com/subject/ciuywctx.html