美文网首页
Android7.0 apptransition主要流程

Android7.0 apptransition主要流程

作者: Lonelyyy | 来源:发表于2017-10-15 00:24 被阅读0次

最近由于工作上的需要,结合一些大神的相关博客与Android源码,大概的把WMS中的app Transition流程给熟悉了一遍,在此写下一些小结

app Transition的主要流程

app Transition代表activity组件的切换过程,启动或是退出activity都会执行app Transition,Android系统定义了多达十几种app Transition类型,这些类型定义在AppTransition.java中
app Transition的过程可以用下图表示。

image.png

在apptransition的过程中,当前的activity会被设置为pause状态,同时窗口也将被设置为invisible,而即将启动的activity被设置为resume状态,窗口设置为visible,这个窗口切换的过程会以动画的形式执行,主要涉及的系统服务有AMS和WMS,本文只讨论窗口切换相关的流程,即WMS部分,AMS的不做涉及。

App Transition的核心步骤是定义在WindowManagerService.java中的3个函数完成,这些函数是随着activity的启动流程而逐步执行的。

public void prepareAppTransition(int transit, boolean alwaysKeepCurrent) {…}
通知wms准备窗口切换操作, transit代表具体的切换类型

public void setAppVisibility(IBinder token, boolean visible) {…}
设置activity窗口的可见性

public void executeAppTransition() {…}
执行窗口切换操作,具体的内容是窗口刷新,根据之前的transit参数选择对应的切换动画并播放

可以用一个流程图表示这一过程

image.png

我们来一一分析这几个重要的函数

prepareAppTransition

WindowManagerService.java

    public void prepareAppTransition(int transit, boolean alwaysKeepCurrent) {
        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                "prepareAppTransition()")) {
            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
        }
        synchronized(mWindowMap) {
            boolean prepared = mAppTransition.prepareAppTransitionLocked(
                    transit, alwaysKeepCurrent);
            if (prepared && okToDisplay()) {
                mSkipAppTransitionAnimation = false;
            }
        }
    }

这个函数的核心是调到了AppTransition.java中的prepareAppTransitionLocked函数,我们来看看具体实现

AppTransition.java

    boolean prepareAppTransitionLocked(int transit, boolean alwaysKeepCurrent) {
        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Prepare app transition:"
                + " transit=" + appTransitionToString(transit)
                + " " + this
                + " alwaysKeepCurrent=" + alwaysKeepCurrent
                + " Callers=" + Debug.getCallers(3));
        if (!isTransitionSet() || mNextAppTransition == TRANSIT_NONE) {
            setAppTransition(transit);
        } else if (!alwaysKeepCurrent) {
            if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) {
                // Opening a new task always supersedes a close for the anim.
                setAppTransition(transit);
            } else if (transit == TRANSIT_ACTIVITY_OPEN
                    && isTransitionEqual(TRANSIT_ACTIVITY_CLOSE)) {
                // Opening a new activity always supersedes a close for the anim.
                setAppTransition(transit);
            }
        }
        boolean prepared = prepare();
        if (isTransitionSet()) {
            mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
            mService.mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, APP_TRANSITION_TIMEOUT_MS);
        }
        return prepared;
    }

其中mNextAppTransition 代表了将要执行的activity组件切换类型,此函数做了这么几件事:
1.如果mNextAppTransition 没有被设置或是设置为TRANSIT_NONE的话,就设置为参数所代表的activity组件切换类型
2.如果mNextAppTransition 已经被设置并且不要求保持mNextAppTransition不变的话,open activity和open task的优先级要高于close activity和close task,前者会覆盖后者
3.执行prepare()函数,返回结果prepared代表app Transition是否已经准备完成
4.向WMS发送一个延时5秒的消息,强制app Transition在5秒内完成

setAppVisibility

如前面流程图所说,这个函数的主要功能是设置窗口的可见性并触发窗口的relayout,这个函数比较长,我们只看关键的部分

WindowManagerService.java

    public void setAppVisibility(IBinder token, boolean visible) {
        synchronized(mWindowMap) {
            wtoken = findAppWindowToken(token); // 1. 通过IBinder对象token找到wtoken(AppWindowToken对象,代表对应的activity窗口)
            ......
            mOpeningApps.remove(wtoken);
            mClosingApps.remove(wtoken); // 2. 把wtoken从mOpeningApps和mClosingApps两个ArraySet中移除
            wtoken.hiddenRequested = !visible; // 3. 重新设置wtoken的可见性
            ......
            if (okToDisplay() && mAppTransition.isTransitionSet()) {.
                ......
                    wtoken.mAppAnimator.setDummyAnimation(); // 4. 给wtoken先设置一个哑动画,等待具体执行时再设置合适的动画
               ......
                if (visible) { // 5. 根据参数visible选择将wtoken重新加入mOpeningApps或是mClosingApps
                    mOpeningApps.add(wtoken);
                } else {
                    mClosingApps.add(wtoken);
                }
                ......
                return;
            }
            ......
             // 6. 通知上层应用窗口的可见性变化(最终传递到ViewRootImpl并触发窗口的布局)
            setTokenVisibilityLocked(wtoken, null, visible, AppTransition.TRANSIT_UNSET, true, wtoken.voiceInteraction);
            wtoken.updateReportedVisibilityLocked(); // 7. 通知AMS窗口的可见性变化
        }
    }

用于设置窗口可见性的函数是setTokenVisibilityLocked,我们后面还会相信分析,现在有个印象即可

executeAppTransition

executeAppTransition是完成前面的步骤后最终执行app Transition的函数

WindowManagerService.java

    public void executeAppTransition() {
        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                "executeAppTransition()")) {
            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
        }

        synchronized(mWindowMap) {
            if (DEBUG_APP_TRANSITIONS) Slog.w(TAG_WM, "Execute app transition: " + mAppTransition
                    + " Callers=" + Debug.getCallers(5));
            if (mAppTransition.isTransitionSet()) {
                mAppTransition.setReady();
                final long origId = Binder.clearCallingIdentity();
                try {
                    mWindowPlacerLocked.performSurfacePlacement();
                } finally {
                    Binder.restoreCallingIdentity(origId);
                }
            }
        }
    }

从代码中不难看出,executeAppTransition是刷新系统UI,在这个过程中会完成窗口可见性变化,窗口动画的设置和播放等过程,具体的流程放到下一篇文章分析

app Transition时序图

用一张时序图总结一下上面的流程

image.png

相关文章

网友评论

      本文标题:Android7.0 apptransition主要流程

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