关于android:Android绘制流程窗口启动流程分析下

7次阅读

共计 6841 个字符,预计需要花费 18 分钟才能阅读完成。

原文转载:https://www.cnblogs.com/tiger-wang-ms/p/6517048.html

三、handleResumeActivity() 流程

在文章结尾贴出的第一段 AcitityThread.handleLauncherActivity() 办法的代码中,执行完 performLaunchAcitity() 创立好 Acitivity 后,便会执行到 handleResumeActivity() 办法,该办法代码如下。

final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        ...// TODO Push resumeArgs into the activity for consideration
        // 该办法执行过程中会调用到 Acitity 的 onResume() 办法,返回的 ActivityClientRecord 对象形容的即是创立好的 Activity     r = performResumeActivity(token, clearHide, reason);

        if (r != null) {
            final Activity a = r.activity;// 返回之前创立的 Acitivty

            if (localLOGV) Slog.v(
                TAG, "Resume" + r + "started activity:" +
                a.mStartedActivity + ", hideForNow:" + r.hideForNow
                + ", finished:" + a.mFinished);

            final int forwardBit = isForward ?
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;

            // If the window hasn't yet been added to the window manager,
            // and this guy didn't finish itself or start another activity,
            // then go ahead and add the window.       // 判断该 Acitivity 是否可见,mStartedAcitity 记录的是一个 Activity 是否还处于启动状态       // 如果还处于启动状态则 mStartedAcitity 为 true,示意该 activity 还未启动好,则该 Activity 还不可见       boolean willBeVisible = !a.mStartedActivity;       // 如果启动的组建不是全屏的,mStartedActivity 也会是 true,此时仍然须要 willBeVisible 为 true 以下的 if 逻辑就是针对这种状况的校对
            if (!willBeVisible) {
                try {willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(a.getActivityToken());
                } catch (RemoteException e) {throw e.rethrowFromSystemServer();
                }
            }
            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;          //PreserverWindow,个别指主题换了或者 configuration 变了状况下的 Acitity 疾速重启机制
                if (r.mPreserveWindow) {
                    a.mWindowAdded = true;
                    r.mPreserveWindow = false;
                    // Normally the ViewRoot sets up callbacks with the Activity
                    // in addView->ViewRootImpl#setView. If we are instead reusing
                    // the decor view we have to notify the view root that the
                    // callbacks may have changed.
                    ViewRootImpl impl = decor.getViewRootImpl();
                    if (impl != null) {impl.notifyChildRebuilt();
                    }
                }
                if (a.mVisibleFromClient && !a.mWindowAdded) {
                    a.mWindowAdded = true;            // 调用了 WindowManagerImpl 的 addView 办法
                    wm.addView(decor, l);
                }

              ...
    }

重点来看 wm.addView() 办法,该办法中的 decor 参数为 Acitity 对应的 Window 中的视图 DecorView,wm 为在创立 PhoneWindow 是创立的 WindowManagerImpl 对象,该对象的 addView 办法理论调用到到是单例对象 WindowManagerGlobal 的 addView 办法(前文有提到)。在看 addView 代码前,我先来看看 WindowManagerGlobal 对象成员变量。

private static WindowManagerGlobal sDefaultWindowManager;
    private static IWindowManager sWindowManagerService;
    private static IWindowSession sWindowSession;

    private final Object mLock = new Object();

    private final ArrayList<View> mViews = new ArrayList<View>();
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();
    private final ArraySet<View> mDyingViews = new ArraySet<View>();

三个成员变量 mViews、mRoots 和 mParams 别离是类型为 View、ViewRootImpl 和 WindowManager.LayoutParams 的数组。这里有这样的逻辑关系,每个 View 都对应着惟一的一个 ViewRootImpl 和 WindowManager.LayoutRarams,即是 1:1:1 的关系。这三个数组长度始终保持统一,并且在同一个地位上寄存的是相互关联的 View、ViewRootImpl 和 WindowManager.LayoutParams 对象。此外还有一个成员变量 mDyView,保留的则是曾经不须要但还未被零碎会收到 View。

View 与 LayoutParams 比拟好了解,那 ViewRootImpl 对象的作用是什么呢?首先 WindowManagerImpl 是作为治理类,就像主管一样,依据 Acitity 和 Window 的调用申请,找到适合的做事的人;DecorView 自身是 FrameworkLayout,本事是一个 View,所示意的是一种动态的构造;所以这里就须要一个真正做事的人,那就是 ViewRootImpl 类的工作。总结来讲 ViewRootImpl 的性能如下

  1. 实现了绘制过程。在 ViewRootImpl 类中,实现了 perfromMeasure()、performDraw()、performLayout() 等绘制相干的办法。
  2. 与零碎服务进行交互,例如与 AcitityManagerSerivice,DisplayService、AudioService 等进行通信,保障了 Acitity 相干性能等失常运行。
  3. 触屏事件等散发逻辑的实现

接下来咱们进入 WindowManagerGlobal.addView() 办法的代码。

public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        ...

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {       ...            // If this is a panel window, then find the window it is being
            // attached to for future reference.       // 如果以后增加的是一个子视图,则还须要找他他的父视图       // 这里咱们剖析的是增加 DecorView 的逻辑,没有父视图,故不会走到这里,panelParentView 为 null       if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {final int count = mViews.size();
                for (int i = 0; i < count; i++) {if (mRoots.get(i).mWindow.asBinder() == wparams.token) {panelParentView = mViews.get(i);
                    }
                }
            }            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);
       // 保留相互对应的 View、ViewRootImpl、WindowManager.LayoutParams 到数组中
            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);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

关注代码中加粗的两个办法,首先会创立一个 ViewRootImpl 对象,而后调用 ViewRootImpl.setView 办法,其中 panelParentView 在 addView 参数为 DecorView 是为 null。进入 ViewRootImpl.setView() 代码。

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {synchronized (this) {if (mView == null) {          // 初始化成员变量 mView、mWindowAttraibutes          //mAttachInfo 是 View 类的一个外部类 AttachInfo 类的对象                // 该类的次要作用就是贮存一组当 View attach 给它的父 Window 的时候 Activity 各种属性的信息                mView = view;
                mAttachInfo.mDisplayState = mDisplay.getState();
                mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);

                mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
                mFallbackEventHandler.setView(view);
                mWindowAttributes.copyFrom(attrs);
                ... // 持续初始化一些变量,蕴含针对 panelParentView 不为 null 时的父窗口的一些解决
          mAdded = true;
                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.          // 这里调用异步刷新申请,最终会调用 performTraversals 办法来实现 View 的绘制          requestLayout();
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {mInputChannel = new InputChannel();
                }
                mForceDecorViewVisibility = (mWindowAttributes.privateFlags
                        & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } catch (RemoteException e) {
                    mAdded = false;
                    mView = null;
                    mAttachInfo.mRootView = null;
                    mInputChannel = null;
                    mFallbackEventHandler.setView(null);
                    unscheduleTraversals();
                    setAccessibilityFocus(null, null);
                    throw new RuntimeException("Adding window failed", e);
                } finally {if (restore) {attrs.restore();
                    }
                }

                ...
            }
        }
    }

相干变量初始化实现后,便会将 mAdded 设置为 true,示意 ViewRootImpl 与 setView 传入的 View 参数曾经做好了关联。之后便会调用 requestLayout() 办法来申请一次异步刷新,该办法起初又会调用到 performTraversals() 办法来实现 view 到绘制工作。留神到这里尽管实现了绘制的工作,然而咱们创立 Activity 的源头是 AMS 中发动的,咱们从一开始创立 Acitivity 到绝对应的 Window、DecorView 这一大套对象时,还并未与 AMS 过程进行反馈。所以之后便会调用 mWindowSession.addToDisplay() 办法会执行 IPC 的跨过程通信,最终调用到 AMS 中的 addWindow 办法来在零碎过程中执行相干加载 Window 的操作。

点击下方链接收费获取 Android 进阶材料:
https://shimo.im/docs/tXXKHgdjPYj6WT8d/

正文完
 0