文章目录

  • 一、 APP 启动白屏 / 黑屏
  • 二、 APP 启动速度测量
    • 1. 通过 Logcat 日志查看应用启动时间
    • 2. 通过 adb 命令查看界面启动时间
  • 三、 APP 冷启动与热启动
  • 四、 APP 启动时间计算

一、 APP 启动白屏 / 黑屏


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

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

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

二、 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

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

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
CompleteC:\Users\octop>

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

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

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

三、 APP 冷启动与热启动


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

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

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

四、 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
CompleteC:\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;

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

  1. 【Android 安全】DEX 加密 ( 多 DEX 加载 | 65535 方法数限制和 MultiDex 配置 | PathClassLoader 类加载源码分析 | DexPathList )

    文章目录 一.65535 方法数限制和 MultiDex 配置 二.多 DEX 加载引入 三.PathClassLoader 类加载源码分析 四.BaseDexClassLoader 类加载源码分析 ...

  2. 【Android 性能优化】应用启动优化 ( 阶段总结 | Trace 文件分析及解决方案 | 源码分析梳理 | 设置主题的方案总结 ) ★

    文章目录 一. 常用的耗时方法优化方案 ( 重要 ) 二. 源码分析梳理 1. 应用启动时间计算相关源码分析 2. Launcher 应用中启动 Android 应用流程 三. 启动白屏解决方案 An ...

  3. android应用启动页面显示不出来了,Android应用中启动页出现白屏如何解决

    Android应用中启动页出现白屏如何解决 发布时间:2020-12-11 14:41:17 来源:亿速云 阅读:100 作者:Leah 今天就跟大家聊聊有关Android应用中启动页出现白屏如何解决 ...

  4. android 7.0 黑屏,Android app启动是出现白屏或者黑屏如何解决?

    1.为什么 APP 启动时会出现白屏或者黑屏? 当打开一个 Activity 时,如果这个 Activity 所属的应用还没有在运行,系统会为这个 Activity 所属的应用创建一个进程,但进程的创 ...

  5. Android APP启动时出现白屏或者黑屏怎么办?

    1.为什么APP启动时会出现白屏或者黑屏? 当打开一个Activity时,如果这个Activity所属的应用还没有在运行,系统会为这个Activity所属的应用创建一个进程,但进程的创建与初始化都需要 ...

  6. android打开app白色页面,完美解决Android App启动页有白屏闪过的问题

    应用启动的时候有短暂的白屏,如图: 可以通过设置theme的方式来解决 @color/colorPrimary @color/colorPrimaryDark @color/colorAccent t ...

  7. 字节跳动Android三面视频解析:framework+MVP架构+HashMap原理+性能优化+Flutter+源码分析等

    前言 对于字节跳动的二面三面而言,Framework+MVP架构+HashMap原理+性能优化+Flutter+源码分析等问题都成高频问点!然而很多的朋友在面试时却答不上或者答不全!今天在这分享下这些 ...

  8. 【Android 逆向】整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析 | /bin/dexopt 源码分析 )

    文章目录 前言 一.DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析 二./bin/dexopt 源码分析 前言 上一篇博客 [Android 逆向]整体加固脱壳 ...

  9. 【Android 电量优化】JobScheduler 源码分析 ( JobServiceContext 源码分析 | 闭环操作总结 | 用户提交任务 | 广播接收者接受相关广播触发任务执行 )★

    文章目录 一.JobServiceContext 引入 二.JobServiceContext 源码分析 三.用户在应用层如何使用 JobScheduler 四.用户提交任务 五.广播接收者监听广播触 ...

最新文章

  1. [WebDev]Web 开发与设计师速查手册大全
  2. 请不要将抛出异常作为业务逻辑使用!!!
  3. java 两行代码解析json文件
  4. LeetCode 875. 爱吃香蕉的珂珂(二分查找)
  5. gpedit msc组策略面板 win10在哪里_Win10家庭版找不到组策略gpedit.msc的解决方法
  6. 宝塔面板之nginx 配置
  7. android9 前台服务通知_Android通知概览
  8. Riverbed“不再只是一家广域网优化公司”
  9. docker java mysql_docker搭建tomcat+mysql容器并部署Java系统
  10. 励志名言名句,2018励志名言名句大全
  11. VMware Workstation Pro安装教程图文详解
  12. oracle、mysql创建用户赋DBA权限
  13. macM1 出现 zsh: command not found: brew问题解决方案
  14. JS密码校验规则前台验证(不能连续字符(如123、abc)连续3位或3位以上)(不能相同字符(如111、aaa)连续3位或3位以上)
  15. 基于easyTrader部署自动化交易(一)
  16. 即席查询(Ad Hoc)如何做到又快又稳?
  17. 搭建个人移动图书馆——Calibre-web
  18. 2023 华为 Datacom-HCIE 真题题库 02/12--含解析
  19. ubuntu期货穿透式监管相关信息查看
  20. 012.[转] 云计算

热门文章

  1. iOS:给标签栏控制器的UITabbarItem添加点击动效
  2. SectionList的使用
  3. java web--servlet(2)
  4. QT删除QWidget或QLayout下的控件
  5. Mysql存储过程中的事务回滚
  6. 201521123022 《Java程序设计》 第十三周学习总结
  7. 交换排序 —— 快速排序
  8. android 实现模拟加载中的程序
  9. FormShortCut MainForm 和 二级FORM
  10. 开发和使用Web用户控件