2021-07-18

本文详细解析了Android appTransition的工作原理,包括其在窗口切换中的关键步骤,如`prepareAppTransition`、`setAppVisibility`和`executeAppTransition`,以及它们在AMS和WMS中的作用。通过流程图和代码分析,带你深入了解appTransition的实现细节。
摘要由CSDN通过智能技术生成

最近由于工作上的需要,结合一些大神的相关博客与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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值