StartingWindow显示流程 - 安卓R

7.0StartingWindow  流程分析 一 定制简单的 StartingWindow <activity android:name=".MainActivity" android:label="@string/app_name" android:theme="@style/AppTheme.StartingWindowTheme"> <!-- 应用启动页(StartingWindow)的theme --> <style name="AppTheme.S... 阅读详情

接着ATMS启动Activity流程中frameworks/base/services/core/java/com/android/server/wm/ActivityStack.java的startActivityLocked方法中调用了frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java的showStartingWindow方法:

    void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch) {
        ......
        final boolean shown = addStartingWindow(packageName, theme,
                compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
                prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
                allowTaskSnapshot(),
                mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal());
        if (shown) {
            mStartingWindowState = STARTING_WINDOW_SHOWN;
        }
    }

调用了ActivityRecord的addStartingWindow方法:

    boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
            CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
            IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
            boolean allowTaskSnapshot, boolean activityCreated) {
        ......
        final ActivityManager.TaskSnapshot snapshot =
                mWmService.mTaskSnapshotController.getSnapshot(task.mTaskId, task.mUserId,
                        false /* restoreFromDisk */, false /* isLowResolution */);
        final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
                allowTaskSnapshot, activityCreated, snapshot);

        if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
            ......
            return createSnapshot(snapshot);
        }
        ......
        // There is no existing starting window, and we don't want to create a splash screen, so
        // that's it!
        if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
            return false;
        }

        ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SplashScreenStartingData");
        mStartingData = new SplashScreenStartingData(mWmService, pkg,
                theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
                getMergedOverrideConfiguration());
        scheduleAddStartingWindow();
        return true;
    }

这里的type主要有两种情况,分别是STARTING_WINDOW_TYPE_SNAPSHOT和STARTING_WINDOW_TYPE_SPLASH_SCREEN。

如果是STARTING_WINDOW_TYPE_SNAPSHOT,则调用了ActivityRecord的createSnapshot方法:

    private boolean createSnapshot(ActivityManager.TaskSnapshot snapshot) {
        ......
        mStartingData = new SnapshotStartingData(mWmService, snapshot);
        scheduleAddStartingWindow();
        return true;
    }

创建了SnapshotStartingData对象mStartingData,最后调用了ActivityRecord的scheduleAddStartingWindow方法。

回到ActivityRecord的addStartingWindow方法中,如果是STARTING_WINDOW_TYPE_SPLASH_SCREEN,则创建了SplashScreenStartingData对象mStartingData,最后也调用了ActivityRecord的scheduleAddStartingWindow方法:

    void scheduleAddStartingWindow() {
        // Note: we really want to do sendMessageAtFrontOfQueue() because we
        // want to process the message ASAP, before any other queued
        // messages.
        if (!mWmService.mAnimationHandler.hasCallbacks(mAddStartingWindow)) {
            ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Enqueueing ADD_STARTING");
            mWmService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
        }
    }

通过mWmService.mAnimationHandler.postAtFrontOfQueue切换到动画线程调用了ActivityRecord的成员变量mAddStartingWindow的run方法:

    private class AddStartingWindow implements Runnable {

        @Override
        public void run() {
            ......
            WindowManagerPolicy.StartingSurface surface = null;
            try {
                surface = startingData.createStartingSurface(ActivityRecord.this);
            } catch (Exception e) {
                Slog.w(TAG, "Exception when adding starting window", e);
            }
            ......
        }
    }

这里调用了之前创建的startingData的createStartingSurface方法,如果是SnapshotStartingData,则调用了frameworks/base/services/core/java/com/android/server/wm/SnapshotStartingData.java的createStartingSurface方法:

    @Override
    StartingSurface createStartingSurface(ActivityRecord activity) {
        return mService.mTaskSnapshotController.createStartingSurface(activity, mSnapshot);
    }

调用了frameworks/base/services/core/java/com/android/server/wm/TaskSnapshotController.java的createStartingSurface方法:

    /**
     * Creates a starting surface for {@param token} with {@param snapshot}. DO NOT HOLD THE WINDOW
     * MANAGER LOCK WHEN CALLING THIS METHOD!
     */
    StartingSurface createStartingSurface(ActivityRecord activity,
            TaskSnapshot snapshot) {
        return TaskSnapshotSurface.create(mService, activity, snapshot);
    }

调用了frameworks/base/services/core/java/com/android/server/wm/TaskSnapshotSurface.java的create方法:

    static TaskSnapshotSurface create(WindowManagerService service, ActivityRecord activity,
            TaskSnapshot snapshot) {

        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
        final Window window = new Window();
        final IWindowSession session = WindowManagerGlobal.getWindowSession();
        window.setSession(session);
        final SurfaceControl surfaceControl = new SurfaceControl();
        ......
        try {
            final int res = session.addToDisplay(window, window.mSeq, layoutParams,
                    View.GONE, activity.getDisplayContent().getDisplayId(), tmpFrame, tmpRect,
                    tmpRect, tmpCutout, null, mTmpInsetsState, mTempControls);
            if (res < 0) {
                Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
                return null;
            }
        } catch (RemoteException e) {
            // Local call.
        }
        final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
                surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, sysUiVis,
                windowFlags, windowPrivateFlags, taskBounds, currentOrientation, activityType,
                insetsState);
        window.setOuter(snapshotSurface);
        try {
            session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
                    tmpFrame, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect,
                    tmpCutout, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
                    mTempControls, sTmpSurfaceSize, sTmpSurfaceControl);
        } catch (RemoteException e) {
            // Local call.
        }

        final Rect systemBarInsets = getSystemBarInsets(tmpFrame, insetsState);
        snapshotSurface.setFrames(tmpFrame, systemBarInsets);
        snapshotSurface.drawSnapshot();
        return snapshotSurface;
    }

通过session.addToDisplay创建了显示窗口(此流程具体见View的添加流程),并创建了TaskSnapshotSurface对象,存放了显示窗口相关信息。

回到ActivityRecord的成员变量mAddStartingWindow的run方法中,如果startingData是SplashScreenStartingData,则调用了frameworks/base/services/core/java/com/android/server/wm/SplashScreenStartingData.java的createStartingSurface方法:

    @Override
    StartingSurface createStartingSurface(ActivityRecord activity) {
        return mService.mPolicy.addSplashScreen(activity.token, mPkg, mTheme, mCompatInfo,
                mNonLocalizedLabel, mLabelRes, mIcon, mLogo, mWindowFlags,
                mMergedOverrideConfiguration, activity.getDisplayContent().getDisplayId());
    }

调用了frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java的addSplashScreen方法:

    /** {@inheritDoc} */
    @Override
    public StartingSurface addSplashScreen(IBinder appToken, int userId, String packageName,
            int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
            int icon, int logo, int windowFlags, Configuration overrideConfig, int displayId) {
        ......

        WindowManager wm = null;
        View view = null;

        try {
            ......
            final PhoneWindow win = new PhoneWindow(context);
            win.setIsStartingWindow(true);
            ......
            params.setTitle("Splash Screen " + packageName);
            addSplashscreenContent(win, context);

            wm = (WindowManager) context.getSystemService(WINDOW_SERVICE);
            view = win.getDecorView();

            if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "Adding splash screen window for "
                + packageName + " / " + appToken + ": " + (view.getParent() != null ? view : null));

            wm.addView(view, params);

            // Only return the view if it was successfully added to the
            // window manager... which we can tell by it having a parent.
            return view.getParent() != null ? new SplashScreenSurface(view, appToken) : null;
        } catch (WindowManager.BadTokenException e) {
            // ignore
            Log.w(TAG, appToken + " already running, starting window not displayed. " +
                    e.getMessage());
        } catch (RuntimeException e) {
            // don't crash if something else bad happens, for example a
            // failure loading resources because we are loading from an app
            // on external storage that has been unmounted.
            Log.w(TAG, appToken + " failed creating starting window", e);
        } finally {
            if (view != null && view.getParent() == null) {
                Log.w(TAG, "view not successfully added to wm, removing view");
                wm.removeViewImmediate(view);
            }
        }

        return null;
    }

通过wm.addView创建显示窗口(此流程具体见View的添加流程),并创建了SplashScreenSurface对象,存放了显示窗口相关信息。

StartingWindow后面是怎样销毁的见StartingWindow销毁流程。

总结

1 StartingWindow分为2种,分别是STARTING_WINDOW_TYPE_SNAPSHOT和STARTING_WINDOW_TYPE_SPLASH_SCREEN。

2 STARTING_WINDOW_TYPE_SNAPSHOT一般显示的是Activity之前的一张截图,如果Activity是secure的,则会显示的内容根据其theme绘制。

3 STARTING_WINDOW_TYPE_SPLASH_SCREEN显示的内容根据Activity的theme绘制。

告别白屏!Android应用启动优化实战:StartingWindow的三种类型与最佳配置指南 本文深入解析Android应用启动优化中的StartingWindow机制,详细介绍Splash Screen、Snapshot和None三种类型的适用场景与最佳配置方案。通过实战代码示例和性能优化技巧,帮助开发者有效解决白屏/黑屏问题,提升应用启动速度和用户体验,特别适合需要优化Android应用启动流程的开发者参考。 阅读详情

相关推荐

Android应用启动白屏/黑屏?从StartingWindow源码角度聊聊冷热启动的优化策略

本文深入解析Android应用启动时白屏/黑屏问题的优化策略,从StartingWindow源码角度剖析冷热启动机制。通过主题优化、动态适配、快照调优等方案,有效提升启动性能与用户体验,并提供了详细的调试工具和架构级实践建议。

weixin_30702441的博客 314

Activity启动窗口(StartingWindow)的添加流程

本篇基于Android Q分析 在Activity启动的时候,Android系统会它一个启动窗口,作用是在应用程序主Activity还没有显示出来的时候,它作为一个预览窗口先让用户能看到一个画面,起到缓冲的作用,我们来分析下启动窗口的添加流程 ActivityStack.startActivityLocked void startActivityLocked(ActivityRecord r, A...

qq_34211365的博客 4940

告别启动白屏!Android StartingWindow 实战:手把手教你定制应用启动闪屏(Splash Screen)

本文深入解析Android StartingWindow机制,提供从白屏到流畅启动体验的完整优化方案。通过SplashScreen API实战演示和StartingWindow深度定制技巧,帮助开发者掌握冷热启动优化、动态主题切换等核心技术,显著提升应用启动性能与用户体验。

weixin_29560063的博客 273

Android T startingwindow流程梳理

startingwindow的一些流程梳理

yimelancholy的博客 7191

App StartingWindow分析

打开WMS的staring window日志 设置WindowManagerDebugConfig的 static final boolean DEBUG_STARTING_WINDOW = true;从log和代码分析 1.setAppStartingWindow 首先针对主题进行检查 有一些主题下是不能显示startingwindow的final boolean windowIsTra

woai110120130的专栏 1941

【实战】ESP32 + LN298N 实现电动推杆的闭环位置伺服控制

本文详细介绍了如何使用ESP32微控制器和LN298N电机驱动模块,为普通电动推杆增加编码器反馈,实现精准的闭环位置伺服控制。文章从硬件选型与接线讲起,深入解析了编码器四倍频计数原理与位置换算,并重点阐述了PID控制算法的核心思想、代码实现及参数整定方法,旨在帮助读者从零构建一个反应迅速、定位精准的智能执行器系统。

weixin_29195615的博客 318

StartingWindow 启动添加显示

一、简介 应用冷启动时候,Activity组件在它的窗口显示出来之前,可以显示一个启动窗口。等应用加载好第一帧之后, 启动窗口消失,显示应用主界面。这个启动窗口可以看作是Activity组件的预览窗口,是由WindowManagerService服务统一管理的,WindowManagerService服务负责启动和结束。 demo_gaitubao_364x619_gaitubao_338...

zxtanshui的专栏 1064

Calibre PEX提参实战:如何用hcell和xcell文件精准屏蔽模块(附避坑指南)

本文深入解析Calibre PEX工具中hcell与xcell文件的协同工作机制,提供模块级寄生参数提取方案。通过实战案例和避坑指南,帮助工程师精准屏蔽已验证IP模块,提升仿真效率和数据一致性,适用于65nm以下工艺节点的复杂SoC设计。

weixin_29275257的博客 629

ActivityManagerService解读之Activity启动闲聊--Activity启动窗口和TaskSnapshot

什么是Activity的启动窗口?为什么存在这样的一个窗口?什么是TaskSnapshot?啥也不说了,直接带着这些个问题开始本篇的闲聊。 什么是Activity的启动窗口,为什么存在这样的一个窗口? 我们先来一个动图直观的了解一下。 首先我们点击启动我们的测试demo,看见蓝色的界面没有,那就是Activity的启动窗口。Android在Activity启动的时候,当应用界面还未显示出来...

为码消得人憔悴 3963

BGE(BAAI General Embedding)模型详解

BGE(BAAI General Embedding)是北京智源人工智能研究院(BAAI)推出的通用文本嵌入模型系列,旨在为各种自然语言处理任务提供高质量的向量表示。

ttyy1112的专栏 7558

【ROS】ROS2导航Nav2:简介、安装、测试效果、错误处理

在ROS2中自动导航使用Nav2来实现。Nav2 使用几个独立的模块化服务,通过 ROS 2接口(例如动作服务器或服务)与行为树 (BT) 通信。Nav2 输入包括:TF转换、一个地图源、一个行为树 (BT) XML 文件和相关的传感器数据源;Nav2 输出速度命令;Nav2 支持多种机器人,比如:四足机器人、履带机器人、轮式机器人等。

郭老二 5086

Android窗口管理服务WindowManagerService显示Activity组件的启动窗口(Starting Window)的过程分析...

在Android系统中,Activity组件在启动之后,并且在它的窗口显示出来之前,可以显示一个启动窗口。这个启动窗口可以看作是Activity组件的预览窗口,是由WindowManagerService服务统一管理的,即由WindowManagerService服务负责启动和结束。在本文中,我们就详细分析WindowManagerService服务启动和结束Activity组...

weixin_30770495的博客 566

使用C/C++复制图像

要使用上述代码,需要将输入图像和输出图像的文件名替换为实际的图像文件名。当程序执行完毕后,将会在当前目录下生成一个名为"output.jpg"的图像文件,其中包含与输入图像完全相同的图像数据。要使用上述代码,需要将输入图像和输出图像的文件名替换为实际的图像文件名。当程序执行完毕后,将会在当前目录下生成一个名为"output.jpg"的图像文件,其中包含与输入图像完全相同的图像数据。函数将输出图像保存到文件中。在这个示例中,我们假设输入图像是一个常见的JPEG图像,文件名为"input.jpg"。

CyberWarpX的博客 730

StartingWindow销毁流程 - 安卓R

1

SSSxCCC的博客 1228

通过WorkVisual连接KUKA机器人的具体方法

通过WorkVisual连接KUKA机器人的具体方法

Robot_PLC_HMI_Automation 6844

Open3D点云数据处理(五):点云、mesh可视化(draw_geometries方法)

本文介绍了Open3D中的draw_geometries可视化方法,可以用于可视化点云和mesh。详细讲述了该方法的各个参数的作用,给出了代码示例。

孙悟空 3140

android9-wms-startingwindow

注:系统级应用(如Launcher)可绕过策略直接控制StartingWindow显示逻辑。

summerkissyou1987的专栏 805

SpringBoot 插件化开发详细总结

SpringBoot 插件化开发方案总结

congge 1万+

Activity显示流程 - 安卓R

1

SSSxCCC的博客 488

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Android APP应用启动页白屏(StartingWindow)优化

转自:https://www.cnblogs.com/whycxb/p/9312914.html 版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 StartingWindow 的处理方式: 使用系统默认的 StartingWindow:用户点了应用图标启动应用,马上弹出系统默认的 StartingWindow(就是做动画的那个 Window) ,等应用加载好第一帧之后,StartingWindow 消失,显示应用第一帧,无缝衔接,体验还不错,这也是通常大部分 Android ..

haima1998的专栏 1096

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

android Application Component研究之Activity(二)

转载地址:http://blog.youkuaiyun.com/windskier/article/details/7172710 上篇文章分析完了task的创建或者复用,接下来接着分析activity在启动过程中还有哪些工作需要去完成?首先给出整个activity的过程图。      1. Starting Window     当该activity运行在新的task中或者进程中时,需要在activ

kc58236582的博客 1007

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

告别启动白屏!Android应用启动优化实战:从StartingWindow源码到自定义闪屏

本文深入解析Android StartingWindow机制,提供从源码分析到品牌化闪屏设计的完整优化方案。通过StartingWindow类型选择、Android 12+ SplashScreen API实战及冷热启动优化策略,帮助开发者解决启动白屏问题,提升应用第一印象。特别针对ActivityRecord和WindowManagerService的交互流程进行详细梳理,实现流畅专业的启动体验。

weixin_33391446的博客 326

Android14 WMS-窗口添加流程(二)-Server端

Android14 WMS-窗口添加流程(一)-Client端-优快云博客本文接着上文"Android14 WMS-窗口添加流程(一)-Client端"往下讲。也就是WindowManagerService#addWindow流程。目录一. WindowManagerService#addWindow标志1:mPolicy.checkAddPermission标志2:getDisplayContentOrCreate标志3: mWindowMap二:窗口类型检查三:新建WindowToken标志1 Win

weixin_41028555的博客 1825
上一篇: Activity生命周期调用流程 - 安卓R
下一篇: Activity的启动流程 - 安卓R
SSSxCCC
博客等级 码龄10年 238粉丝 74原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SSSxCCC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值