Android T 远程动画显示流程(更新中)
序
本地动画和远程动画区别是什么?
本地动画:自给自足。对自身SurfaceControl矢量动画进行控制。
远程动画:拿来吧你!一个app A对另一个app B通过binder跨进程通信,控制app B的SurfaceControl矢量动画。
无论是本地动画还是远程动画,都仅仅只是对SurfaceControl动画图层控制,而无法控制应用内部的View。
注:矢量动画包含位移、放大、缩小、透明度、圆角等。
常见的远程动画,就是桌面与应用交互。比如,我们从桌面点击一个应用启动这个应用,这个过程中会产生的动画就是远程动画。
我们从这个角度分析其动画显示过程。
显示过程分析
我们前面通过学习Android T 窗口动画(本地动画)显示流程,发现无论什么类型动画都有其创建和移除的过程,在SurfaceAnimator中createAnimationLeash和removeLeash添加log打印堆栈信息。
createAnimationLeash
添加log
Slog.i("WindowManager","createAnimationLeash type = " + animationTypeToString(type) + " animatable = "+animatable, new Exception());
removeLeash
添加log
Slog.i("WindowManager","removeLeash leash = " + leash , new Exception());
我们看看下面几种启动的动画创建和移除的过程(排除了insets类型的动画):
冷启动
WindowManager: createAnimationLeash type = app_transition animatable = Task{d0b86 #77 type=standard A=10116:com.example.mysystemdialog}
WindowManager: createAnimationLeash type = app_transition animatable = Task{2c8eb49 #1 type=home}
WindowManager: createAnimationLeash type = window_animation animatable = WallpaperWindowToken{79ea104 token=android.os.Binder@30f6996}
WindowManager: removeLeash leash = Surface(name=Surface(name=Task=1)/@0x50de32e - animation-leash of app_transition)/@0x5e2271f
WindowManager: removeLeash leash = Surface(name=Surface(name=Task=77)/@0xeb831c3 - animation-leash of app_transition)/@0xebdcd79
WindowManager: removeLeash leash = Surface(name=Surface(name=WallpaperWindowToken{79ea104 token=android.os.Binder@30f6996})/@0xa32d428 - animation-leash of window_animation)/@0xd323396
WindowManager: createAnimationLeash type = starting_reveal animatable = Window{a65f40b u0 com.example.mysystemdialog/com.example.mysystemdialog.MainActivity}
WindowManager: createAnimationLeash type = window_animation animatable = Window{dad6bc2 u0 Splash Screen com.example.mysystemdialog}
WindowManager: removeLeash leash = Surface(name=Surface(name=a65f40b com.example.mysystemdialog/com.example.mysystemdialog.MainActivity)/@0xdbce2c1 - animation-leash of starting_reveal)/@0x6df31a7
WindowManager: removeLeash leash = Surface(name=Surface(name=dad6bc2 Splash Screen com.example.mysystemdialog)/@0x3868f87 - animation-leash of window_animation)/@0x9d22add
应用不在后台运行,从桌面点击一个应用冷启动,动画顺序如下:
| 动画窗口 | 动画类型 | 操作 |
|---|---|---|
| mysystemdialog(Task) | app_transition | 创建 |
| home(桌面Task) | app_transition | 创建 |
| WallpaperWindowToken(壁纸) | window_animation | 创建 |
| home(桌面Task) | app_transition | 移除 |
| mysystemdialog(Task) | app_transition | 移除 |
| WallpaperWindowToken(壁纸) | app_transition | 移除 |
| MainActivity冷启动应用主界面(ActivityRecord) | starting_reveal | 创建 |
| mysystemdialog的冷启动窗口(Splash Screen) | window_animation | 创建 |
| MainActivity冷启动应用主界面(ActivityRecord) | starting_reveal | 移除 |
| mysystemdialog的冷启动窗口(Splash Screen) | window_animation | 移除 |
热启动
WindowManager: createAnimationLeash type = app_transition animatable = Task{d0b86 #77 type=standard A=10116:com.example.mysystemdialog}
WindowManager: createAnimationLeash type = app_transition animatable = Task{2c8eb49 #1 type=home}
WindowManager: createAnimationLeash type = window_animation animatable = WallpaperWindowToken{79ea104 token=android.os.Binder@30f6996}
WindowManager: removeLeash leash = Surface(name=Surface(name=Task=1)/@0x50de32e - animation-leash of app_transition)/@0x6c5dc4f
WindowManager: removeLeash leash = Surface(name=Surface(name=Task=77)/@0xeb831c3 - animation-leash of app_transition)/@0x8775329
WindowManager: removeLeash leash = Surface(name=Surface(name=WallpaperWindowToken{79ea104 token=android.os.Binder@30f6996})/@0xa32d428 - animation-leash of window_animation)/@0x8534d86
WindowManager: createAnimationLeash type = window_animation animatable = Window{d22fcb2 u0 SnapshotStartingWindow for taskId=77}
WindowManager: removeLeash leash = Surface(name=Surface(name=d22fcb2 SnapshotStartingWindow for taskId=77)/@0xfcbebd0 - animation-leash of window_animation)/@0x3faeece
应用本身就在后台运行,从桌面热启动应用,动画顺序如下:
| 动画窗口 | 动画类型 | 操作 |
|---|---|---|
| mysystemdialog(Task) | app_transition | 创建 |
| home(桌面Task) | app_transition | 创建 |
| WallpaperWindowToken(壁纸) | window_animation | 创建 |
| home(桌面Task) | app_transition | 移除 |
| mysystemdialog(Task) | app_transition | 移除 |
| WallpaperWindowToken(壁纸) | app_transition | 移除 |
| mysystemdialog的热启动窗口(SnapshotStartingWindow) | window_animation | 创建 |
| mysystemdialog的热启动窗口(SnapshotStartingWindow) | window_animation | 移除 |
home回到桌面
WindowManager: createAnimationLeash type = app_transition animatable = Task{2c8eb49 #1 type=home}
WindowManager: createAnimationLeash type = app_transition animatable = Task{d0b86 #77 type=standard A=10116:com.example.mysystemdialog}
WindowManager: createAnimationLeash type = window_animation animatable = WallpaperWindowToken{79ea104 token=android.os.Binder@30f6996}
WindowManager: removeLeash leash = Surface(name=Surface(name=Task=77)/@0xeb831c3 - animation-leash of app_transition)/@0x77da703
WindowManager: removeLeash leash = Surface(name=Surface(name=Task=1)/@0x50de32e - animation-leash of app_transition)/@0x12ce9bd
WindowManager: removeLeash leash = Surface(name=Surface(name=WallpaperWindowToken{79ea104 token=android.os.Binder@30f6996})/@0xa32d428 - animation-leash of window_animation)/@0x5e69f0a
在应用界面,点击home键退回到桌面界面,动画顺序如下:
| 动画窗口 | 动画类型 | 操作 |
|---|---|---|
| home(桌面Task) | app_transition | 创建 |
| mysystemdialog(Task) | app_transition | 创建 |
| WallpaperWindowToken(壁纸) | window_animation | 创建 |
| mysystemdialog(Task) | app_transition | 移除 |
| home(桌面Task) | app_transition | 移除 |
| WallpaperWindowToken(壁纸) | window_animation | 移除 |
关键堆栈
创建动画 createAnimationLeash
桌面
WindowManager: createAnimationLeash type = app_transition animatable = Task{2c8eb49 #1 type=home}
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.createAnimationLeash(SurfaceAnimator.java:472)
WindowManager: at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:186)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2810)
WindowManager: at com.android.server.wm.WindowContainer$AnimationRunnerBuilder.lambda$build$4(WindowContainer.java:4078)
WindowManager: at com.android.server.wm.WindowContainer$AnimationRunnerBuilder.$r8$lambda$BWeVZQp29j72z9D_sWdID2xR4qI(Unknown Source:0)
WindowManager: at com.android.server.wm.WindowContainer$AnimationRunnerBuilder$$ExternalSyntheticLambda1.startAnimation(Unknown Source:7)
WindowManager: at com.android.server.wm.WindowContainer.applyAnimationUnchecked(WindowContainer.java:3174)
WindowManager: at com.android.server.wm.Task.applyAnimationUnchecked(Task.java:3366)
WindowManager: at com.android.server.wm.WindowContainer.applyAnimation(WindowContainer.java:2958)
WindowManager: at com.android.server.wm.AppTransitionController.applyAnimations(AppTransitionController.java:882)
WindowManager: at com.android.server.wm.AppTransitionController.applyAnimations(AppTransitionController.java:1085)
WindowManager: at com.android.server.wm.AppTransitionController.handleAppTransitionReady(AppTransitionController.java:266)
WindowManager: at com.android.server.wm.RootWindowContainer.checkAppTransitionReady(RootWindowContainer.java:970)
WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:834)
WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:777)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:115)
WindowManager: at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:57)
WindowManager: at android.os.Handler.handleCallback(Handler.java:942)
WindowManager: at android.os.Handler.dispatchMessage(Handler.java:99)
WindowManager: at android.os.Looper.loopOnce(Looper.java:201)
WindowManager: at android.os.Looper.loop(Looper.java:288)
WindowManager: at android.os.HandlerThread.run(HandlerThread.java:67)
WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:44)
应用task
WindowManager: createAnimationLeash type = app_transition animatable = Task{d0b86 #77 type=standard A=10116:com.example.mysystemdialog}
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.createAnimationLeash(SurfaceAnimator.java:472)
WindowManager: at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:186)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2810)
WindowManager: at com.android.server.wm.WindowContainer$AnimationRunnerBuilder.lambda$build$4(WindowContainer.java:4078)
WindowManager: at com.android.server.wm.WindowContainer$AnimationRunnerBuilder.$r8$lambda$BWeVZQp29j72z9D_sWdID2xR4qI(Unknown Source:0)
WindowManager: at com.android.server.wm.WindowContainer$AnimationRunnerBuilder$$ExternalSyntheticLambda1.startAnimation(Unknown Source:7)
WindowManager: at com.android.server.wm.WindowContainer.applyAnimationUnchecked(WindowContainer.java:3174)
WindowManager: at com.android.server.wm.Task.applyAnimationUnchecked(Task.java:3366)
WindowManager: at com.android.server.wm.WindowContainer.applyAnimation(WindowContainer.java:2958)
WindowManager: at com.android.server.wm.AppTransitionController.applyAnimations(AppTransitionController.java:882)
WindowManager: at com.android.server.wm.AppTransitionController.applyAnimations(AppTransitionController.java:1087)
WindowManager: at com.android.server.wm.AppTransitionController.handleAppTransitionReady(AppTransitionController.java:266)
WindowManager: at com.android.server.wm.RootWindowContainer.checkAppTransitionReady(RootWindowContainer.java:970)
WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:834)
WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:777)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:115)
WindowManager: at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:57)
WindowManager: at android.os.Handler.handleCallback(Handler.java:942)
WindowManager: at android.os.Handler.dispatchMessage(Handler.java:99)
WindowManager: at android.os.Looper.loopOnce(Looper.java:201)
WindowManager: at android.os.Looper.loop(Looper.java:288)
WindowManager: at android.os.HandlerThread.run(HandlerThread.java:67)
WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:44)
壁纸
WindowManager: createAnimationLeash type = window_animation animatable = WallpaperWindowToken{79ea104 token=android.os.Binder@30f6996}
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.createAnimationLeash(SurfaceAnimator.java:472)
WindowManager: at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:186)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2810)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2817)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2823)
WindowManager: at com.android.server.wm.WallpaperAnimationAdapter.lambda$startWallpaperAnimations$0(WallpaperAnimationAdapter.java:82)
WindowManager: at com.android.server.wm.WallpaperAnimationAdapter.$r8$lambda$pFt1sM34mQb-FFZsZckZ6IVTj_M(Unknown Source:0)
WindowManager: at com.android.server.wm.WallpaperAnimationAdapter$$ExternalSyntheticLambda0.accept(Unknown Source:13)
WindowManager: at com.android.server.wm.WallpaperWindowToken.forAllWallpaperWindows(WallpaperWindowToken.java:214)
WindowManager: at com.android.server.wm.WindowContainer.forAllWallpaperWindows(WindowContainer.java:1911)
WindowManager: at com.android.server.wm.WindowContainer.forAllWallpaperWindows(WindowContainer.java:1911)
WindowManager: at com.android.server.wm.WindowContainer.forAllWallpaperWindows(WindowContainer.java:1911)
WindowManager: at com.android.server.wm.WindowContainer.forAllWallpaperWindows(WindowContainer.java:1911)
WindowManager: at com.android.server.wm.WindowContainer.forAllWallpaperWindows(WindowContainer.java:1911)
WindowManager: at com.android.server.wm.WindowContainer.forAllWallpaperWindows(WindowContainer.java:1911)
WindowManager: at com.android.server.wm.WallpaperAnimationAdapter.startWallpaperAnimations(WallpaperAnimationAdapter.java:78)
WindowManager: at com.android.server.wm.RemoteAnimationController.createWallpaperAnimations(RemoteAnimationController.java:270)
WindowManager: at com.android.server.wm.RemoteAnimationController.goodToGo(RemoteAnimationController.java:185)
WindowManager: at com.android.server.wm.AppTransition.goodToGo(AppTransition.java:419)
WindowManager: at com.android.server.wm.AppTransitionController.handleAppTransitionReady(AppTransitionController.java:277)
WindowManager: at com.android.server.wm.RootWindowContainer.checkAppTransitionReady(RootWindowContainer.java:970)
WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:834)
WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:777)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:115)
WindowManager: at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:57)
WindowManager: at android.os.Handler.handleCallback(Handler.java:942)
WindowManager: at android.os.Handler.dispatchMessage(Handler.java:99)
WindowManager: at android.os.Looper.loopOnce(Looper.java:201)
WindowManager: at android.os.Looper.loop(Looper.java:288)
WindowManager: at android.os.HandlerThread.run(HandlerThread.java:67)
WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:44)
starting_reveal
WindowManager: createAnimationLeash type = starting_reveal animatable = Window{f64bf2d u0 com.example.mysystemdialog/com.example.mysystemdialog.MainActivity}
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.createAnimationLeash(SurfaceAnimator.java:472)
WindowManager: at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:186)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2810)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2817)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2823)
WindowManager: at com.android.server.wm.TaskOrganizerController.applyStartingWindowAnimation(TaskOrganizerController.java:634)
WindowManager: at com.android.server.wm.TaskOrganizerController.removeStartingWindow(TaskOrganizerController.java:696)
WindowManager: at com.android.server.wm.StartingSurfaceController$StartingSurface.remove(StartingSurfaceController.java:271)
WindowManager: at com.android.server.wm.ActivityRecord.lambda$removeStartingWindowAnimation$4(ActivityRecord.java:2787)
WindowManager: at com.android.server.wm.ActivityRecord.$r8$lambda$cZFIJhaFFrS84y2PDOOXTP_CRFs(Unknown Source:0)
WindowManager: at com.android.server.wm.ActivityRecord$$ExternalSyntheticLambda16.run(Unknown Source:4)
WindowManager: at com.android.server.wm.ActivityRecord.removeStartingWindowAnimation(ActivityRecord.java:2803)
WindowManager: at com.android.server.wm.ActivityRecord.removeStartingWindow(ActivityRecord.java:2732)
WindowManager: at com.android.server.wm.ActivityRecord.onFirstWindowDrawn(ActivityRecord.java:6577)
WindowManager: at com.android.server.wm.WindowState.performShowLocked(WindowState.java:4674)
WindowManager: at com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked(WindowStateAnimator.java:274)
WindowManager: at com.android.server.wm.DisplayContent.lambda$new$8(DisplayContent.java:1099)
WindowManager: at com.android.server.wm.DisplayContent.$r8$lambda$OtLCIQFjCt9o-SYztyeDUcWUwGs(Unknown Source:0)
WindowManager: at com.android.server.wm.DisplayContent$$ExternalSyntheticLambda10.accept(Unknown Source:4)
WindowManager: at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:2684)
WindowManager: at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:2674)
WindowManager: at com.android.server.wm.WindowState.applyInOrderWithImeWindows(WindowState.java:4942)
WindowManager: at com.android.server.wm.WindowState.forAllWindows(WindowState.java:4786)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1672)
WindowManager: at com.android.server.wm.DisplayContent.applySurfaceChangesTransaction(DisplayContent.java:4946)
WindowManager: at com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction(RootWindowContainer.java:1014)
WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:816)
WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:777)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:115)
WindowManager: at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:57)
WindowManager: at android.os.Handler.handleCallback(Handler.java:942)
WindowManager: at android.os.Handler.dispatchMessage(Handler.java:99)
WindowManager: at android.os.Looper.loopOnce(Looper.java:201)
WindowManager: at android.os.Looper.loop(Looper.java:288)
WindowManager: at android.os.HandlerThread.run(HandlerThread.java:67)
WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:44)
冷启动窗口
WindowManager: createAnimationLeash type = window_animation animatable = Window{4d28c0 u0 Splash Screen com.example.mysystemdialog}
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.createAnimationLeash(SurfaceAnimator.java:472)
WindowManager: at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:186)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2810)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2817)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2823)
WindowManager: at com.android.server.wm.WindowState.startAnimation(WindowState.java:5327)
WindowManager: at com.android.server.wm.WindowState.startAnimation(WindowState.java:5303)
WindowManager: at com.android.server.wm.WindowStateAnimator.applyAnimationLocked(WindowStateAnimator.java:652)
WindowManager: at com.android.server.wm.WindowManagerService.tryStartExitingAnimation(WindowManagerService.java:2642)
WindowManager: at com.android.server.wm.WindowManagerService.relayoutWindow(WindowManagerService.java:2448)
WindowManager: at com.android.server.wm.Session.relayout(Session.java:253)
WindowManager: at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:727)
WindowManager: at com.android.server.wm.Session.onTransact(Session.java:178)
WindowManager: at android.os.Binder.execTransactInternal(Binder.java:1285)
WindowManager: at android.os.Binder.execTransact(Binder.java:1244)
热启动窗口
WindowManager: createAnimationLeash type = window_animation animatable = Window{d22fcb2 u0 SnapshotStartingWindow for taskId=77}
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.createAnimationLeash(SurfaceAnimator.java:472)
WindowManager: at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:186)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2810)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2817)
WindowManager: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2823)
WindowManager: at com.android.server.wm.WindowState.startAnimation(WindowState.java:5327)
WindowManager: at com.android.server.wm.WindowState.startAnimation(WindowState.java:5303)
WindowManager: at com.android.server.wm.WindowStateAnimator.applyAnimationLocked(WindowStateAnimator.java:652)
WindowManager: at com.android.server.wm.WindowState.removeIfPossible(WindowState.java:2593)
WindowManager: at com.android.server.wm.WindowState.removeIfPossible(WindowState.java:2487)
WindowManager: at com.android.server.wm.WindowManagerService.removeWindow(WindowManagerService.java:2053)
WindowManager: at com.android.server.wm.Session.remove(Session.java:230)
WindowManager: at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:687)
WindowManager: at com.android.server.wm.Session.onTransact(Session.java:178)
WindowManager: at android.os.Binder.execTransactInternal(Binder.java:1285)
WindowManager: at android.os.Binder.execTransact(Binder.java:1244)
移除动画 removeLeash
桌面
0WindowManager: removeLeash leash = Surface(name=Surface(name=Task=1)/@0x50de32e - animation-leash of app_transition)/@0x12ce9bd
0WindowManager: java.lang.Exception
0WindowManager: at com.android.server.wm.SurfaceAnimator.removeLeash(SurfaceAnimator.java:423)
0WindowManager: at com.android.server.wm.SurfaceAnimator.reset(SurfaceAnimator.java:413)
0WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$0(SurfaceAnimator.java:132)
0WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$lRxTVOJy8fX752UbrFno9INW9hE(Unknown Source:0)
0WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda1.run(Unknown Source:8)
0WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$1(SurfaceAnimator.java:144)
0WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$4PiCdaEsT4mA6LQVhqpeM5EoU9c(Unknown Source:0)
0WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda0.onAnimationFinished(Unknown Source:4)
0WindowManager: at com.android.server.wm.RemoteAnimationController.onAnimationFinished(RemoteAnimationController.java:307)
0WindowManager: at com.android.server.wm.RemoteAnimationController.-$$Nest$monAnimationFinished(Unknown Source:0)
0WindowManager: at com.android.server.wm.RemoteAnimationController$FinishedCallback.onAnimationFinished(RemoteAnimationController.java:418)
0WindowManager: at android.view.IRemoteAnimationFinishedCallback$Stub.onTransact(IRemoteAnimationFinishedCallback.java:89)
0WindowManager: at android.os.Binder.execTransactInternal(Binder.java:1285)
0WindowManager: at android.os.Binder.execTransact(Binder.java:1244)
应用task
WindowManager: removeLeash leash = Surface(name=Surface(name=Task=77)/@0xeb831c3 - animation-leash of app_transition)/@0x77da703
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.removeLeash(SurfaceAnimator.java:423)
WindowManager: at com.android.server.wm.SurfaceAnimator.reset(SurfaceAnimator.java:413)
WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$0(SurfaceAnimator.java:132)
WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$lRxTVOJy8fX752UbrFno9INW9hE(Unknown Source:0)
WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda1.run(Unknown Source:8)
WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$1(SurfaceAnimator.java:144)
WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$4PiCdaEsT4mA6LQVhqpeM5EoU9c(Unknown Source:0)
WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda0.onAnimationFinished(Unknown Source:4)
WindowManager: at com.android.server.wm.RemoteAnimationController.onAnimationFinished(RemoteAnimationController.java:307)
WindowManager: at com.android.server.wm.RemoteAnimationController.-$$Nest$monAnimationFinished(Unknown Source:0)
WindowManager: at com.android.server.wm.RemoteAnimationController$FinishedCallback.onAnimationFinished(RemoteAnimationController.java:418)
WindowManager: at android.view.IRemoteAnimationFinishedCallback$Stub.onTransact(IRemoteAnimationFinishedCallback.java:89)
WindowManager: at android.os.Binder.execTransactInternal(Binder.java:1285)
WindowManager: at android.os.Binder.execTransact(Binder.java:1244)
壁纸
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.removeLeash(SurfaceAnimator.java:423)
WindowManager: at com.android.server.wm.SurfaceAnimator.reset(SurfaceAnimator.java:413)
WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$0(SurfaceAnimator.java:132)
WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$lRxTVOJy8fX752UbrFno9INW9hE(Unknown Source:0)
WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda1.run(Unknown Source:8)
WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$1(SurfaceAnimator.java:144)
WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$4PiCdaEsT4mA6LQVhqpeM5EoU9c(Unknown Source:0)
WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda0.onAnimationFinished(Unknown Source:4)
WindowManager: at com.android.server.wm.RemoteAnimationController.onAnimationFinished(RemoteAnimationController.java:322)
WindowManager: at com.android.server.wm.RemoteAnimationController.-$$Nest$monAnimationFinished(Unknown Source:0)
WindowManager: at com.android.server.wm.RemoteAnimationController$FinishedCallback.onAnimationFinished(RemoteAnimationController.java:418)
WindowManager: at android.view.IRemoteAnimationFinishedCallback$Stub.onTransact(IRemoteAnimationFinishedCallback.java:89)
WindowManager: at android.os.Binder.execTransactInternal(Binder.java:1285)
WindowManager: at android.os.Binder.execTransact(Binder.java:1244)
starting_reveal
WindowManager: removeLeash leash = Surface(name=Surface(name=f64bf2d com.example.mysystemdialog/com.example.mysystemdialog.MainActivity)/@0xdf5580d - animation-leash of starting_reveal)/@0x6af05d3
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.removeLeash(SurfaceAnimator.java:423)
WindowManager: at com.android.server.wm.SurfaceAnimator.reset(SurfaceAnimator.java:413)
WindowManager: at com.android.server.wm.SurfaceAnimator.cancelAnimation(SurfaceAnimator.java:364)
WindowManager: at com.android.server.wm.SurfaceAnimator.cancelAnimation(SurfaceAnimator.java:270)
WindowManager: at com.android.server.wm.WindowContainer.cancelAnimation(WindowContainer.java:2832)
WindowManager: at com.android.server.wm.WindowState.lambda$removeIfPossible$2(WindowState.java:2503)
WindowManager: at com.android.server.wm.WindowState.$r8$lambda$gtdPXCAzSiavwVZY5OZGcTDMs84(Unknown Source:0)
WindowManager: at com.android.server.wm.WindowState$$ExternalSyntheticLambda0.apply(Unknown Source:2)
WindowManager: at com.android.server.wm.WindowState.applyInOrderWithImeWindows(WindowState.java:4942)
WindowManager: at com.android.server.wm.WindowState.forAllWindows(WindowState.java:4786)
WindowManager: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1655)
WindowManager: at com.android.server.wm.WindowState.removeIfPossible(WindowState.java:2501)
WindowManager: at com.android.server.wm.WindowState.removeIfPossible(WindowState.java:2487)
WindowManager: at com.android.server.wm.WindowManagerService.removeWindow(WindowManagerService.java:2053)
WindowManager: at com.android.server.wm.Session.remove(Session.java:230)
WindowManager: at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:687)
WindowManager: at com.android.server.wm.Session.onTransact(Session.java:178)
WindowManager: at android.os.Binder.execTransactInternal(Binder.java:1285)
WindowManager: at android.os.Binder.execTransact(Binder.java:1244)
冷启动窗口
WindowManager: removeLeash leash = Surface(name=Surface(name=4d28c0 Splash Screen com.example.mysystemdialog)/@0xbbbe9b3 - animation-leash of window_animation)/@0x7ca9ee9
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.removeLeash(SurfaceAnimator.java:423)
WindowManager: at com.android.server.wm.SurfaceAnimator.reset(SurfaceAnimator.java:413)
WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$0(SurfaceAnimator.java:132)
WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$lRxTVOJy8fX752UbrFno9INW9hE(Unknown Source:0)
WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda1.run(Unknown Source:8)
WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$1(SurfaceAnimator.java:144)
WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$4PiCdaEsT4mA6LQVhqpeM5EoU9c(Unknown Source:0)
WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda0.onAnimationFinished(Unknown Source:4)
WindowManager: at com.android.server.wm.LocalAnimationAdapter.lambda$startAnimation$0(LocalAnimationAdapter.java:67)
WindowManager: at com.android.server.wm.LocalAnimationAdapter.$r8$lambda$gPDCFw0mQLltlXqA3mL6IUKCwLs(Unknown Source:0)
WindowManager: at com.android.server.wm.LocalAnimationAdapter$$ExternalSyntheticLambda0.run(Unknown Source:6)
WindowManager: at android.os.Handler.handleCallback(Handler.java:942)
WindowManager: at android.os.Handler.dispatchMessage(Handler.java:99)
WindowManager: at android.os.Looper.loopOnce(Looper.java:201)
WindowManager: at android.os.Looper.loop(Looper.java:288)
WindowManager: at android.os.HandlerThread.run(HandlerThread.java:67)
WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:44)
热启动窗口
WindowManager: removeLeash leash = Surface(name=Surface(name=d22fcb2 SnapshotStartingWindow for taskId=77)/@0xfcbebd0 - animation-leash of window_animation)/@0x3faeece
WindowManager: java.lang.Exception
WindowManager: at com.android.server.wm.SurfaceAnimator.removeLeash(SurfaceAnimator.java:423)
WindowManager: at com.android.server.wm.SurfaceAnimator.reset(SurfaceAnimator.java:413)
WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$0(SurfaceAnimator.java:132)
WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$lRxTVOJy8fX752UbrFno9INW9hE(Unknown Source:0)
WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda1.run(Unknown Source:8)
WindowManager: at com.android.server.wm.SurfaceAnimator.lambda$getFinishedCallback$1(SurfaceAnimator.java:144)
WindowManager: at com.android.server.wm.SurfaceAnimator.$r8$lambda$4PiCdaEsT4mA6LQVhqpeM5EoU9c(Unknown Source:0)
WindowManager: at com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda0.onAnimationFinished(Unknown Source:4)
WindowManager: at com.android.server.wm.LocalAnimationAdapter.lambda$startAnimation$0(LocalAnimationAdapter.java:67)
WindowManager: at com.android.server.wm.LocalAnimationAdapter.$r8$lambda$gPDCFw0mQLltlXqA3mL6IUKCwLs(Unknown Source:0)
WindowManager: at com.android.server.wm.LocalAnimationAdapter$$ExternalSyntheticLambda0.run(Unknown Source:6)
WindowManager: at android.os.Handler.handleCallback(Handler.java:942)
WindowManager: at android.os.Handler.dispatchMessage(Handler.java:99)
WindowManager: at android.os.Looper.loopOnce(Looper.java:201)
WindowManager: at android.os.Looper.loop(Looper.java:288)
WindowManager: at android.os.HandlerThread.run(HandlerThread.java:67)
WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:44)
小结
从当前分析以及堆栈来看,应用的启动窗口相关动画(冷启动应用主界面starting_reveal、冷启动窗口Splash Screen、热启动窗口SnapshotStartingWindow)均为本地动画,其他的动画均为远程动画。
本地动画:
窗口类型:冷启动应用主界面starting_reveal、冷启动窗口Splash Screen、热启动窗口SnapshotStartingWindow。
代码逻辑:创建动画时,从applyAnimationLocked流程到createAnimationLeash;移除动画时,从LocalAnimationAdapter的Callback到removeLeash流程。
注:starting_reveal类型动画比较特殊,涉及到StartingWindow动画流程。
远程动画:
窗口类型:桌面Task、应用Task、壁纸。
代码逻辑:创建动画时,从handleAppTransitionReady流程到createAnimationLeash;移除动画时,从IRemoteAnimationFinishedCallback流程到removeLeash流程。
动画添加流程
动画移除流程
相关文章:
Android T 远程动画显示流程(更新中)
序 本地动画和远程动画区别是什么? 本地动画:自给自足。对自身SurfaceControl矢量动画进行控制。 远程动画:拿来吧你!一个app A对另一个app B通过binder跨进程通信,控制app B的SurfaceControl矢量动画。 无论是本地动画还是远程…...
【计算机网络】【练习题及解答】【新加坡南洋理工大学】【Computer Control Network】
说明: 仅供学习使用。 一、题目描述 题目共4问,描述网络通信中的 帧传输时延(Frame Delay)、传播时延(Propagation Delay),以及 链接利用率(Link Utilization) 的相关…...
云计算HCIE备考经验分享
大家好,我是来自深圳信息职业技术学院22级鲲鹏3-1班的刘同学,在2023年9月19日成功通过了华为云计算HCIE认证,并且取得了A的成绩。下面把我的考证经验分享给大家。 转专业进鲲鹏班考HCIE 大一上学期的时候,在上Linux课程的时候&…...
Threejs API——`OrbitControls`相机控件
文章目录 API用法API OrbitControls 相机控制用法 导入import {OrbitControls } from three/examples/jsm/controls/OrbitControls.js import {DRACOLoader,AmbientLight,Color,MOUSE,...
远程教育:低代码在教育技术领域的重塑之力
新冠肺炎大流行对世界各地的行业产生了影响,其中一些行业的影响远远超过其他行业。食品、零售、供应链、娱乐和航空业是受影响最大的行业,为确保不间断运营,这引发了一场数字革命。相信,这种数字化的采用将长期保持下去࿰…...
vue 模板语法值class操作
class.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>class</title><!-- 确保引入正确的Vue版本库,下面只是示例,需要替换为实际可工作的CDN地址 --><sc…...
MySQL的原生API实现插入数据后在可视化工具上不显示的问题解决
显示表中有两行数据,该表也设置了主键和唯一索引 点进表里看却没有数据 问题原因出现在这里,虽然很多常用的数据库连接池都会开启自动提交,但ibatis的SqlSession使用sessionFactory.openSession()创建时,默认的自动提交是false&am…...
Blender教程(基础)-内插面、分离、环切、倒角-08
一、内插面 菜单位置如下图位置。 单击需要处理的面,出现一个黄色的圈。 1、菜单选中内插 鼠标悬停在黄色圈内单击左键可以来回实现内插,但是发现并不好操作。 2、快捷键内插 在选中需要操作的面之后,鼠标移动到外面,键盘在英…...
Unity 自动轮播、滑动轮播
如图所示,可设置轮播间隔,可左右滑动进行轮播 1.在UGUI创建个Image,添加自动水平组件 2.添加并配置脚本 3.代码如下,都有注释 using UnityEngine; using UnityEngine.UI;public class IndicatorManager : MonoBehaviour {public …...
纯html+js+css个人博客
首页 <!DOCTYPE html> <html><head><meta http-equiv"Content-Type" content"text/html; charsetutf-8"><title>主页</title><!-- 引入layui css文件 --><link rel"stylesheet" href"layui-…...
二百二十一、HiveSQL报错:return code 2 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask
一、目的 在运行HiveSQL时,执行报错 tatement: FAILED: Execution Error, return code 2 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask 二、在yarn上查看任务报错 The required MAP capability is more than the supported max container capability in t…...
JavaEE学习笔记 2024-1-25 --VUE的入门使用
上一篇 个人整理非商业用途,欢迎探讨与指正!! 文章目录 14.VUE基础14.1VUE的入门使用14.2条件判断14.3循环渲染14.4v-bind绑定标签属性14.5v-model表单标签的双向绑定14.6事件处理14.7axios 14.VUE基础 前端框架 UI框架:页面渲染Bootstrap,L…...
php-fpm详细讲解
PHP-FPM(FastCGI Process Manager)是PHP的一种运行模式,用于处理动态HTTP请求。 它与传统的模块式PHP(如Apache模块)相比,将PHP解析和执行过程单独封装为一个独立的进程池,通过FastCGI协议与We…...
小白水平理解面试经典题目LeetCode 455 Assign Cookies【Java实现】
455 分配cookies 小白渣翻译: 假设你是一位很棒的父母,想给你的孩子一些饼干。但是,你最多应该给每个孩子一块饼干。 每个孩子 i 都有一个贪婪因子 g[i] ,这是孩子满意的 cookie 的最小大小;每个 cookie j 都有一个…...
uniapp 问题汇总-问题数(2)
ios scroll-view无法滚动 使用uview折叠面板嵌套scroll-view 嵌套之后安卓可以滚动,ios无法滚动 <u-collapse accordion opencollapseOpen changecollapseChange ref"uCollapse" :valueuCollapseValue><u-collapse-item :nameindex :title&quo…...
[AG32VF407]国产MCU+FPGA Verilog编写控制2路gpio输出不同频率方波实验
视频讲解 [AG32VF407]国产MCUFPGA Verilog编写控制2路gpio输出不同频率方波实验 实验过程 根据原理图,选择两个pin脚作为输出 修改VE文件,clk选择PIN_OSC,使用内部晶振8Mhz,gpio使用PIN_51和52,pinout是数组 添加pll…...
python coding with ChatGPT 打卡第15天| 二叉树:翻转二叉树、对称二叉树
相关推荐 python coding with ChatGPT 打卡第12天| 二叉树:理论基础 python coding with ChatGPT 打卡第13天| 二叉树的深度优先遍历 python coding with ChatGPT 打卡第14天| 二叉树的广度优先遍历 文章目录 翻转二叉树Key Points相关题目视频讲解重点分析递归遍历…...
Python(19)Excel表格操作Ⅰ
目录 导包 读取EXCEL文件 1、获取worksheet名称 2、设定当前工作表 3、输出目标单元格数据 4、工作表.rows(行) 5、工作表.columns(列) 小结 导包 要想使用 python 操作 Excel 文件,应当导入 openpyxl 包。在…...
HiveSQL题——聚合函数(sum/count/max/min/avg)
目录 一、窗口函数的知识点 1.1 窗户函数的定义 1.2 窗户函数的语法 1.3 窗口函数分类 聚合函数 排序函数 前后函数 头尾函数 1.4 聚合函数 二、实际案例 2.1 每个用户累积访问次数 0 问题描述 1 数据准备 2 数据分析 3 小结 2.2 各直播间最大的同时在线人数 …...
计算机是什么做的
背景 虽然我是科班出身的,但是上大学时候,对这些内容并不感兴趣,只是简单的进行做题,考试而已。并没有思考,为啥学计算机组成原理,模电数电,微机原理,单片机,操作系统啥…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
C语言中提供的第三方库之哈希表实现
一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...
