基于Android R版本分析
参考:
Android11 WMS 之 AppTransition;
android R版本AppTransition动效源码分析;
Activity Transit Type
| TRANSIT Type | value | desc |
|---|---|---|
| TRANSIT_UNSET | -1 | 初始值,未设置过渡动画 |
| TRANSIT_NONE | 0 | 没有过渡动画 |
| TRANSIT_ACTIVITY_OPEN | 6 | 新Activity的窗口正在同一任务中的现有窗口之上打开 |
| TRANSIT_ACTIVITY_CLOSE | 7 | 最顶层Activity的窗口正在关闭以显示同一任务中的前一个Activity |
| TRANSIT_TASK_OPEN | 8 | 新Activity的窗口正在另一个Activity所属的Task的现有窗口之上打开 |
| TRANSIT_TASK_CLOSE | 9 | 最顶层Activity的一个窗口正在关闭,以显示不同任务中的前一个Activity |
| TRANSIT_TASK_TO_FRONT | 10 | 将Task移至最顶端,即现有Task的窗口显示在另一个Activity所属Task的顶部 |
| TRANSIT_TASK_TO_BACK | 11 | 将Task移至最低端,即现有Task的窗口被放置在所有其他Task下方 |
| TRANSIT_WALLPAPER_CLOSE | 12 | 新Activity没有Wallpaper的窗口会在有Wallpaper的窗口之上打开,从而有效地关闭Wallpaper |
| TRANSIT_WALLPAPER_OPEN | 13 | 新Activity带有Wallpaper的窗口会在没有Wallpaper的窗口上打开,从而有效地打开Wallpaper |
| TRANSIT_WALLPAPER_INTRA_OPEN | 14 | 新Activity的一个窗口在现有Activity的顶部打开,并且两者都在Wallpaper的顶部 |
| TRANSIT_WALLPAPER_INTRA_CLOSE | 15 | 最顶部Activity的窗口正在关闭以显示之前的Activity,并且两者都位于Wallpaper的顶部 |
| TRANSIT_TASK_OPEN_BEHIND | 16 | 新Task中的一个窗口在另一个Activity的Task中的现有窗口后面打开 新窗口将短暂显示,然后消失 |
| TRANSIT_ACTIVITY_RELAUNCH | 18 | 正在重新启动Activity(例如,由于配置更改) |
| TRANSIT_DOCK_TASK_FROM_RECENTS | 19 | 正在对接最近的Task |
| TRANSIT_KEYGUARD_GOING_AWAY | 20 | Keyguard 即将消失 |
| TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER | 21 | Keyguard 将消失,显示背后请求Wallpaper的Activity |
| TRANSIT_KEYGUARD_OCCLUDE | 22 | Keyguard 被遮挡 |
| TRANSIT_KEYGUARD_UNOCCLUDE | 23 | Keyguard 未被遮挡 |
| TRANSIT_TRANSLUCENT_ACTIVITY_OPEN | 24 | 正在打开一个半透明的Activity |
| TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE | 25 | 一个半透明的Activity正在关闭 |
| TRANSIT_CRASHING_ACTIVITY_CLOSE | 26 | 正在关闭崩溃的Activity |
| TRANSIT_TASK_CHANGE_WINDOWING_MODE | 27 | 一项Task正在改变窗口模式 |
| TRANSIT_SHOW_SINGLE_TASK_DISPLAY | 28 | 由于第一个Activity已启动或正在打开,因此正在显示只能包含一个Task的显示 |
APP 冷启动
我们知道,在launcher界面冷启动一个应用程序,需要涉及三个进程:
- launcher进程:负责与SystemServer进程通信,通知拉起目标app进程,同时处理Pause逻辑;
- systemserver进程:负责fork目标进程,同时需要等待launcher进程和目标app进程的执行结果,待都准备就绪之后,真正启动目标进程;
- 目标app进程:接收System进程的启动通知,进行初始化,等待SystemServer通知可以正式启动;
该图中包含了热启动的逻辑,我们只需要关注冷启动逻辑即可,但其实也是类同的,在一部分逻辑上,冷启动和热启动的执行逻辑相同;
上述的时序图,对应的就是整体的目标app冷启动的调用栈逻辑;
我们针对两个调用逻辑进行分析:
-
TargetStack:startActivityLocked
在这个过程中,会对Starting Activity的Task准备AppTransition,在后续目标进程启动的过程中,会执行execute AppTransition;
-
RootWindowContainer:resumeFocusedStackTopActivities
- 将之前的Activity进行PAUSED;
- 将目标Activity(即将需要显示的Activity)设置为resume状态;
TargetStack # startActivityLocked
在这个过程中,其实核心逻辑有两部分:
- prepareAppTransition:这个过程本质就是调用AppTransition的setAppTransition()方法,将对应计算出来的tranist和flag保存到AppTransition以供后续使用;
- startingWindow:这个是Android R引入的一个新的概念,是用于处理在应用进程刚启动时,大概率会出现的1-2s的空白界面的优化,使用特定的画面遮挡这一块显示区域,对应的概念为Splash Screen;
activityPaused
同理,也包含热启动的逻辑
在调用完目前TargetTask执行prepareAppTransition()方法之后,就会继续对原Activity进行Pause操作;
核心逻辑其实就是ActivityStack的completePausedLocked(),其中包含了两个部分:
- Pausing Activity的处理
- Resume Activity的处理
我们分析一下Pausing Activity处理逻辑;
Pausing Activity
基本上针对PausingActivity的处理,在launcher冷启动的场景下,其实就是将mPausingActivity的state设置为PAUSED,然后将mPausingActivity置空即可;
resumeNext # resumeFocusedStacksTopActivities
我们关注冷启动的流程,我们可以看到,在 !next.attachedToProcess的分支中,我们会调用ActivityStackSupervisor的startSpecificActivity()方法,在这个方法中,有一个核心逻辑:
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
final WindowProcessController wpc =
mService.getProcessController(r.processName, r.info.applicationInfo.uid);
boolean knownToBeDead = false;
// 这个过程会判断wpc是否为空,即判断目标进程的ProcessRecord实例是否为空
// 如果为空,这不会进入该分支执行realStartActivityLocked()方法
if (wpc != null && wpc.hasThread()) {
try {
realStartActivityLocked(r, wpc, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
knownToBeDead = true;
}
r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
final boolean isTop = andResume && r.isTopRunningActivity();
mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}
attachApplication
在这个过程中,会获取目标进程的ProcessRecord实例,然后从中获取对应的ProcessRecord的WindowProcessController实例;
WindowProcessController用于和AMS中的ProcessRecord进行通讯,当ProcessRecord中对应用进程作出调整后,通过WindowProcessController和WM进行通信;
ATMS会获取到目标ProcessRecord的WindowProcessController实例,传给对应的WindowContainer,即对应的ActivityRecord,推动ActivityRecord执行对应的逻辑,最终就是调用RootWindowContainer的realStartActivityLocked()进行真正的Activity启动;
我们需要注意的是,Application的启动和Activity的启动,不是同一时刻,可见简单的理解为Application为进程,只有当进程启动之后,Activity才能基于该基础之上机型启动和创建;
realStartActivityLocked
这个过程,针对冷启动,比较简单,会在realStartActivityLocked()方法中执行minimalResumeActivityLocked()方法,这个过程中就会调用ActivityRecord的completeResumeLocked,进而执行executeAppTransition()方法;
performSurfacePlacement
真正进行动画绘制的逻辑,在goodTogo()模块;
这个模块中,会判断startingWindow(Splash Screen)和对应的目标ActivityRecord的窗口动画是否绘制完成,完成之后,就可以进行show显示;
而这一块的动画本质,其实还是ValueAnimator的使用,但是这个里面涉及到了远程动画和本地动画的区别;