【Android 性能优化】应用启动优化 ( 启动白屏问题 | 应用启动时间测量 | 冷启动 | 热启动 | 应用启动时间计算源码分析 )

简介: 【Android 性能优化】应用启动优化 ( 启动白屏问题 | 应用启动时间测量 | 冷启动 | 热启动 | 应用启动时间计算源码分析 )

文章目录

一、 APP 启动白屏 / 黑屏

二、 APP 启动速度测量

1. 通过 Logcat 日志查看应用启动时间

2. 通过 adb 命令查看界面启动时间

三、 APP 冷启动与热启动

四、 APP 启动时间计算





一、 APP 启动白屏 / 黑屏


1 . 问题描述 : Android 应用启动时 , 尤其是大型复杂的应用 , 经常出现几秒钟的白屏或黑屏 , 黑屏或白屏取决于主界面 Activity 的主题风格 ;



2 . 解决方案 : Android 应用启动时很多大型应用都会有一个几秒的倒计时 , 并配上动态广告 , 这并不是开发者想要放上去的 , 而是为了避免上述启动白屏导致用户体很差 ;



3 . 启动优化 : 这里的应用启动白屏 / 黑屏的时间 , 是可以通过优化解决的 , 如将 3 33 秒钟的启动白屏卡顿 , 优化为毫秒级 ;






二、 APP 启动速度测量




1. 通过 Logcat 日志查看应用启动时间


通过 Logcat 日志查看应用启动时间 : 该方法只适用于 Android 4.4 版本之后的手机 ;



① 使用工具 : 使用 Android Studio 中的 Logcat 日志查看工具 ;


② 过滤选项 : 设置过滤选项为 No Filters , 这是系统 ActivityTaskManager 打印的 , 不属于应用日志信息 ;


③ 关键字 : 使用 Display 关键字过滤 ;


④ 截取到的日志信息如下 :


2020-06-20 08:44:09.821 1266-1305/? I/ActivityTaskManager: Displayed kim.hsl.recyclerview/.MainActivity: +334ms
2020-06-20 08:44:18.457 1266-1305/? I/ActivityTaskManager: Displayed 
com.google.android.permissioncontroller/com.android.packageinstaller.permission.ui.GrantPermissionsActivity: +315ms
2020-06-20 08:44:22.308 1266-1305/? I/ActivityTaskManager: Displayed kim.hsl.cckfa/.MainActivity: +311ms


⑤ 具体操作选项参考下面的截图 :


image.png




2. 通过 adb 命令查看界面启动时间




通过 adb 命令查看界面启动时间 :



① 命令格式 : adb shell am start -W 包名/完整 Activity 类名 ;


② 本次命令 : adb shell am start -W kim.hsl.rtmp/kim.hsl.rtmp.MainActivity , 其中 kim.hsl.rtmp 是包名 , kim.hsl.rtmp.MainActivity 是完整的类名 ;


Microsoft Windows [版本 10.0.18362.900]
(c) 2019 Microsoft Corporation。保留所有权利。
C:\Users\octop>adb shell am start -W kim.hsl.rtmp/kim.hsl.rtmp.MainActivity
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] 
cmp=kim.hsl.rtmp/.MainActivity }
Status: ok
LaunchState: COLD
Activity: kim.hsl.rtmp/.MainActivity
TotalTime: 374
WaitTime: 376
Complete
C:\Users\octop>


③ 命名截图 : 下面的截图作为参考 ;


image.png


④ Activity 界面源码 : 上述启动类类对应 RTMP_Pusher 应用中的主界面 ;


package kim.hsl.rtmp;
public class MainActivity extends AppCompatActivity {
  //...
}




三、 APP 冷启动与热启动


热启动的速度要远高于冷启动 ;



1 . 冷启动 : 应用后台没有该应用 , 该应用所有资源都要重新加载 , 分配新的进程 , 初始化 Application , 初始化 Activity 界面 ; 下图中的 LanuchState 中显示了启动的模式 , 下图中显示的是冷启动 ;


image.png



2 . 热启动 : 按下 Home 键 , 应用进入后台 , 再次启动 , 应用由后台转到前台 , 这种启动称为热启动 ; 下图中的 LanuchState 中显示了启动的模式 , 下图中显示的是热启动 ;




image.png




四、 APP 启动时间计算


1 . 启动 Activity 命令 : adb shell am start -W 包名/完整 Activity 类名 ;



2 . 日志打印内容 :


C:\Users\octop>adb shell am start -W kim.hsl.rtmp/kim.hsl.rtmp.MainActivity
Starting: Intent { act=android.intent.action.MAIN 
cat=[android.intent.category.LAUNCHER] cmp=kim.hsl.rtmp/.MainActivity }
Status: ok
LaunchState: COLD
Activity: kim.hsl.rtmp/.MainActivity
TotalTime: 431
WaitTime: 433
Complete
C:\Users\octop>




3 . am 命令及源码 : 在上述命令中可以启动 Android 应用 Activity 界面 , 其中 am 命令是由 Am.java 程序编译出来的 , 其路径是 \frameworks\base\cmds\am\src\com\android\commands\am\Am.java ;




4 . 分析 Am.java 可执行文件 :



① 执行启动 Activity 相关逻辑 : 启动前后都记录了时间 , 整个启动过程就是通过这两个时间计算出来的 ;


IActivityManager.WaitResult result = null;
int res;
// 记录开始时间
final long startTime = SystemClock.uptimeMillis();
if (mWaitOption) {
    // 启动 Activity 
    result = mAm.startActivityAndWait(null, null, intent, mimeType,
                null, null, 0, mStartFlags, profilerInfo, null, mUserId);
    res = result.result;
} else {
    res = mAm.startActivityAsUser(null, null, intent, mimeType,
            null, null, 0, mStartFlags, profilerInfo, null, mUserId);
}
// 记录结束时间
final long endTime = SystemClock.uptimeMillis();


② 打印启动时间相关源码 : IActivityManager.WaitResult 对象中封装了 thisTime , totalTime 等时间信息 ; 这些时间都是在启动过程中计算的 ;


if (mWaitOption && launched) {
    if (result == null) {
        result = new IActivityManager.WaitResult();
        result.who = intent.getComponent();
    }
    System.out.println("Status: " + (result.timeout ? "timeout" : "ok"));
    if (result.who != null) {
        System.out.println("Activity: " + result.who.flattenToShortString());
    }
    if (result.thisTime >= 0) {
        System.out.println("ThisTime: " + result.thisTime);
    }
    if (result.totalTime >= 0) {
        System.out.println("TotalTime: " + result.totalTime);
    }
    System.out.println("WaitTime: " + (endTime-startTime));
    System.out.println("Complete");
}



5 . 分析启动时间计算源码 :



① 计算启动时间源码 : APP 启动时间计算在 \frameworks\base\services\core\java\com\android\server\am\ActivityRecord.java 类中计算 ;


② 在 windowsDrawn 方法中调用 reportLaunchTimeLocked 计算时间 :


public void windowsDrawn() {
    synchronized(service) {
        if (displayStartTime != 0) {
          // 该方法是入口方法
            reportLaunchTimeLocked(SystemClock.uptimeMillis());
        }
        mStackSupervisor.sendWaitingVisibleReportLocked(this);
        startTime = 0;
        finishLaunchTickingLocked();
        if (task != null) {
            task.hasBeenVisible = true;
        }
    }
}


③ 启动时间计算 : 可以看到在 reportLaunchTimeLocked 方法中 , 计算了 thisTime 和 totalTime 的时间值 ;


 

private void reportLaunchTimeLocked(final long curTime) {
        final ActivityStack stack = task.stack;
        // 这里计算了 APP 启动时间
        final long thisTime = curTime - displayStartTime;
        final long totalTime = stack.mLaunchStartTime != 0
                ? (curTime - stack.mLaunchStartTime) : thisTime;
        if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
            Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching", 0);
            EventLog.writeEvent(EventLogTags.AM_ACTIVITY_LAUNCH_TIME,
                    userId, System.identityHashCode(this), shortComponentName,
                    thisTime, totalTime);
            StringBuilder sb = service.mStringBuilder;
            sb.setLength(0);
            sb.append("Displayed ");
            sb.append(shortComponentName);
            sb.append(": ");
            TimeUtils.formatDuration(thisTime, sb);
            if (thisTime != totalTime) {
                sb.append(" (total ");
                TimeUtils.formatDuration(totalTime, sb);
                sb.append(")");
            }
            Log.i(ActivityManagerService.TAG, sb.toString());
        }
        mStackSupervisor.reportActivityLaunchedLocked(false, this, thisTime, totalTime);
        if (totalTime > 0) {
            //service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime);
        }
        displayStartTime = 0;
        stack.mLaunchStartTime = 0;
    }


6 . APP 启动时间总结 :



① 开始时间 : 点击 APP 图标 , 该时间就是 Am.java 中记录的 startTime 开始时间 ;


// 记录开始时间
final long startTime = SystemClock.uptimeMillis();


② 系统分配内存时间 : 之后 Android 系统会给 APP 分配内存 , 这段时间是无法进行优化的 , 用户无法控制 , 占用时间由系统控制 ;


③ 画面绘制完毕调用方法 : 当调用 ActivityRecord.java 中的 windowsDrawn 方法时 , 画面绘制完毕 , 此时会调用 reportLaunchTimeLocked 方法 , 传入当前时间 SystemClock.uptimeMillis() 作为参数 ;


   

if (displayStartTime != 0) {
          // 该方法是入口方法
            reportLaunchTimeLocked(SystemClock.uptimeMillis());
        }


④ 画面绘制时间 : 在 reportLaunchTimeLocked 方法中 , 计算 thisTime 时间 , curTime 是传入的 SystemClock.uptimeMillis() 参数 , 即当前时间 , displayStartTime 是画面开始绘制的时间 , thisTime 就是画面绘制时间 ;


final ActivityStack stack = task.stack;
final long thisTime = curTime - displayStartTime;


⑤ 总时间计算 : 这里计算总时间时 , 需要根据当前是冷启动还是热启动进行不同的计算 , 如果是冷启动 , (curTime - stack.mLaunchStartTime) 时间是总时间 , thisTime 是热启动的启动总时间 ;


final long totalTime = stack.mLaunchStartTime != 0
        ? (curTime - stack.mLaunchStartTime) : thisTime;



相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
目录
相关文章
|
存储 Android开发
如何查看Flutter应用在Android设备上已被撤销的权限?
如何查看Flutter应用在Android设备上已被撤销的权限?
867 64
|
12月前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
1245 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
存储 消息中间件 人工智能
【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡
【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡
766 10
【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡
|
JavaScript Linux 网络安全
Termux安卓终端美化与开发实战:从下载到插件优化,小白也能玩转Linux
Termux是一款安卓平台上的开源终端模拟器,支持apt包管理、SSH连接及Python/Node.js/C++开发环境搭建,被誉为“手机上的Linux系统”。其特点包括零ROOT权限、跨平台开发和强大扩展性。本文详细介绍其安装准备、基础与高级环境配置、必备插件推荐、常见问题解决方法以及延伸学习资源,帮助用户充分利用Termux进行开发与学习。适用于Android 7+设备,原创内容转载请注明来源。
6726 77
|
缓存 编解码 Android开发
Android内存优化之图片优化
本文主要探讨Android开发中的图片优化问题,包括图片优化的重要性、OOM错误的成因及解决方法、Android支持的图片格式及其特点。同时介绍了图片储存优化的三种方式:尺寸优化、质量压缩和内存重用,并详细讲解了相关的实现方法与属性。此外,还分析了图片加载优化策略,如异步加载、缓存机制、懒加载等,并结合多级缓存流程提升性能。最后对比了几大主流图片加载框架(Universal ImageLoader、Picasso、Glide、Fresco)的特点与适用场景,重点推荐Fresco在处理大图、动图时的优异表现。这些内容为开发者提供了全面的图片优化解决方案。
600 1
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
1167 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
Dart 前端开发 Android开发
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
703 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
522 14
|
12月前
|
移动开发 前端开发 Android开发
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
1950 12
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
12月前
|
移动开发 Rust JavaScript
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
1307 4
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡

热门文章

最新文章