DecorView添加到Window的流程

Quibbler 2021-3-3 752

DecorView添加到Window的流程


        在Activity的组成结构一文中,了解了Activity的组成,内部持有Window实例,再由这个Window管理布局。Activity中的Window何时被创建并被添加到Activity中的呢?DecorView是如何被加载到Window中的。



1、Window的创建

        在Activity启动流程全新版本一文中,详细捋清了Activity的启动流程。顺着继续往下看,让我们跟随Activity的启动流程找到答案。


        在ActivityThread中的handleLaunchActivity(...)方法中,处理系统服务的创建Activity回调:

    /**
     * Extended implementation of activity launch. Used when server requests a launch or relaunch.
     */
    @Override
    public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
        ...
        final Activity a = performLaunchActivity(r, customIntent);
        ...
    }

        内部调用另一个方法performLaunchActivity(...)执行真正的Activity创建和初始化相关操作:

    /**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        try {
            ...
                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, r.configCallback,
                        r.assistToken);
                ...
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                ...
            }
                ...
        return activity;
    }

        上面的方法中有重要的两步操作:attach(...)Activity生命周期的onCreate()回调。

    final void attach(Context context,...) {
        attachBaseContext(context);
        mFragments.attachHost(null /*parent*/);
        
        //Activity内部持有的Window实现类是PhoneWindow
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(mWindowControllerCallback);
        mWindow.setCallback(this);
        ...
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        
        mUiThread = Thread.currentThread();
        mMainThread = aThread;
        ...
        mWindowManager = mWindow.getWindowManager();
    }

        初始化Activity内部持有的Window,实现现类是PhoneWindow,继承自Window

        通过WindowsetWindowManager(...)方法给Window设置窗口管理器。

        再通过Window获取到WindowManager赋值给Activity中的全局变量mWindowManager

        这里完成了Activity中Window、WindowManager相关的初始化工作。关于Window详见理解Window一文,关于WindowManager详见理解WindowManager一文。

        


2、DecorView的创建

        Activity创建完毕,内部持有的Window也初始化了。继续跟随着Activity的启动流程,完成剩下DecorView添加到Window中的过程。


        在Activity启动流程全新版本一文第4.6节知道Activity的onResume()生命周期是通过系统服务发起ResumeActivityItem回调,最终执行ActivityThreadhandleResumeActivity(...)

    @Override
    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
        ...
        // TODO Push resumeArgs into the activity for consideration
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, 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;
            ...
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                }
            }
        ...
    }

        handleResumeActivity(...)处理onResume()生命周期回调,内部通过WindowgetDecorView()方法获取DecorView实例。getDecorView()方法在抽象类Window还未被实现,前面提到过Activity中的Window实现是PhoneWindowgetDecorView()方法实现如下:

    @Override
    public final @NonNull View getDecorView() {
        if (mDecor == null || mForceDecorInstall) {
            installDecor();
        }
        return mDecor;
    }

        通过PhoneWindowinstallDecor()方法安装DecorViewWindow中:

    private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            mDecor = generateDecor(-1);
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            ...
        } else {
            mDecor.setWindow(this);
        }
        
        //对mDecor进行各种属性、Style设置
        ...
    }

        如果PhoneWindow中的mDecor还未被创建,那么就调用generateDecor(int featureId)方法生成一个DecorView

    protected DecorView generateDecor(int featureId) {
        // System process doesn't have application context and in that case we need to directly use
        // the context we have. Otherwise we want the application context, so we don't cling to the
        // activity.
        Context context;
        ...
        return new DecorView(context, featureId, this, getAttributes());
    }

        


3、DecorView添加到Window

        通过Window拿到DecorView后回到ActivityThreadhandleResumeActivity(...)方法中继续

    @Override
    public void handleResumeActivity(IBinder token,boolean finalStateRequest,boolean isForward,String reason) {
        ...
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
        ...
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
            
            //通过Activity获取WindowManager,在第一节我们知道在attach()中初始化
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            ...
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    //把decor添加到WindowManager中
                    wm.addView(decor, l);
                }
            }
        ...
    }

        通过Activity获取WindowManager实例wm,在第一节我们知道Activity中的WindowManagerattach(...)中初始化。WindowManager继承自ViewManager。都是关于Window的接口。通过WindowManager将DecorView添加到Window中:

    //把decor添加到WindowManager中
    wm.addView(decor, l);

        WindowManager接口的实现类是WindowManagerImpladdView()方法实现:

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());
    }

        其实WindowManagerImpl中的大部分操作都是通过内部的WindowManagerGlobal完成

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow, int userId) {
            ...
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
            // do this last because it fires off messages to start doing things
            try {
                root.setView(view, wparams, panelParentView, userId);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

        在这里创建ViewRootImpl--它不是View,实现了ViewParent接口,作为View和WindowManager之间的桥梁。通过setView(...)将从ActivityThread层层传递过来的DecorView添加到当前Activity的Window中。

        

        到这里DecorView被添加到Window中管理,接下来就开始了View的绘制流程:measure、layout、draw。详见View的绘制流程

        


不忘初心的阿甘
最新回复 (0)
    • 安卓笔记本
      2
        登录 注册 QQ
返回
仅供学习交流,切勿用于商业用途。如有错误欢迎指出:fluent0418@gmail.com