Android 勇闯高阶性能优化之启动优化篇

目录
  • 🔥 背景
  • 🔥 启动内部机制
    • 💥 冷启动
      • 🌀 创建 Application
      • 🌀 创建Activity
    • 💥 热启动
    • 💥 温启动
  • 🔥 查询的启动时间
    • 💥 初始显示时间(Time to initial display)
    • 💥 完全显示时间(Time to full display)
  • 🔥 性能迟缓分析
    • 💥 Application 初始化
    • 💥 Activity初始化
      • 🌀 布局优化
      • 🌀 代码优化
  • 🔥 阻塞实验
    • 💥 Application 阻塞 2秒, Activity 阻塞 2秒
      • 🌀 SccApp.class
      • 🌀 MainActivity.class
    • 💥 将Appliacation 和Activity阻塞的2秒都放在工作线程去操作
  • 🔥 APP 启动黑/白屏
    • 💥 优雅的解决黑白屛

🔥 背景

用户不会在乎你的项目是不是过大,里面是不是有很多初始化的逻辑。他只在乎你-慢了。

所以咱们这篇文章有两个目的:

启动速度提升(用户眼中的大神就是你)

优化代码逻辑和规范(别让自己成为继任者中的XX)

今天咱们就来了解一下应用启动内部机制和启动速度优化。

🔥 启动内部机制

应用有三种启动状态:

  • 冷启动;
  • 温启动;
  • 热启动。

💥 冷启动

冷启动是指应用从头开始:冷启动发生在设备启动后第一次启动应用程序 (Zygote>fork>app) ,或系统关闭应用程序后。

在冷启动开始时,系统有三个任务。 这些任务是:

  • 加载和启动应用程序。
  • 启动后立即显示应用程序的空白启动页面。
  • 创建应用程序进程。

一旦系统创建了应用程序进程,应用程序进程就负责接下来的阶段:

  • 创建应用的实体。
  • 启动主线程。
  • 创建主页面。
  • 绘制页面上的View。
  • 布局页面。
  • 执行首次的绘制。

如下图:

  • Displayed Time:初始显示时间
  • reportFullyDrawn():完全显示的时间

注意:在创建 Application 和创建 Activity 期间可能会出现性能问题。

🌀 创建 Application

当应用程序启动时,空白启动页面保留在屏幕上,直到系统首次完成应用程序的绘制。

如果你重写了Application.onCreate(),系统将调用Application 上的onCreate()方法。之后,应用程序生成主线程,也称为UI线程,并将创建主Activity的任务交给它。

🌀 创建Activity

应用进程创建你的Activity后,Activity会执行以下操作:

  • 初始化值。
  • 调用构造函数。
  • 调用 Activity 当前生命周期状态的回调方法,如 Activity.onCreate()。

注意:onCreate() 方法对加载时间的影响最大,因为它执行开销最高的工作:加载UI的布局和渲染,以及初始化Activity运行所需的对象。

💥 热启动

热启动时,系统将应用从后台拉回前台,应用程序的 Activity 在内存中没有被销毁,那么应用程序可以避免重复对象初始化,UI的布局和渲染。

如果 Activity 被销毁则需要重新创建。

和冷启动的区别: 不需要创建 Application。

💥 温启动

温启动介于冷启动和热启动中间吧。例如:

用户按返回键退出应用,然后重新启动。进程可能还没有被杀死,但应用必须通过调用onCreate()重新创建 Activity。

系统回收了应用的内存,然后用户重新运行应用。应用进程和Activity都需要重新启动。

咱们看看他们共同消耗多长时间。

🔥 查询的启动时间

💥 初始显示时间(Time to initial display)

在 Android 4.4(API 级别 19)及更高版本中,logcat 包含一个输出行,其中包含一个名为 Displayed 的值。 此值表示启动流程和完成在屏幕上绘制相应活动之间经过的时间量。 经过的时间包含以下事件序列:

  • 启动进程。
  • 初始化对象。
  • 创建并初始化Activity。
  • 加载布局。
  • 第一次绘制你的应用程序。

注意这里查看日志需要如下操作:

报告的日志行类,如下图:

//冷启动
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +1s355ms
//温启动(进程被杀死)
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +1s46ms
//热启动
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +289ms
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +253ms

图例讲解:

第一个时间,冷启动时间:+1s355ms;

然后我们在后台杀死进程,再次启动应用;

第二个时间,温启动时间:+1s46ms;

这里咱们在后台杀死进程所以:应用进程和Activity需要重新启动。

第三个时间:热启动时间:+289ms 和 +253ms;

按返回键,仅退出activity。所以耗时比较短。

当然整体看这个应用开启时间并不长,因为 Demo 的 Application 和 Activity 都没有进行太多的操作。

💥 完全显示时间(Time to full display)

你可以使用 reportFullyDrawn() 方法来测量应用程序启动和所有资源和视图层次结构的完整显示之间经过的时间。在应用程序执行延迟加载的情况下,这可能很有价值。在延迟加载中,应用程序不会阻止窗口的初始绘制,而是异步加载资源并更新视图层次结构。

这里我在Activity.onCreate()中加了个工作线程。并在里面调用reportFullyDrawn() 方法。代码如下:

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.e(this.getClass().getName(), "onCreate");
    setContentView(R.layout.activity_main);
    ...
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(3000);
                reportFullyDrawn();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

报告的日志行类,如下图:

I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s970ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s836ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s107ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s149ms

图例讲解:

然后你会发现界面出来好一会才打这个日志。看到这里我觉得好多人已经知道怎么去优化启动速度了。

🔥 性能迟缓分析

看到上面的实验其实三种启动情况,受我们影响的方面在于 application 和 activity 。

💥 Application 初始化

当你的代码覆盖 Application 对象并在初始化该对象时执行繁重的工作或复杂的逻辑时,启动性能可能会受到影响。 产生的原因包括:

  • 应用程序的初始onCreate()函数。如:执行了不需要立即执行的初始化。
  • 应用程序初始化的任何全局单例对象。如:一些不必要的对象。
  • 可能发生的任何磁盘I/O、反序列化或紧密循环。

解决方案

无论问题在于不必要的初始化还是磁盘I/O,解决方案都是延迟初始化。换句话说,你应该只初始化立即需要的对象。不要创建全局静态对象,而是转向单例模式,应用程序只在第一次需要时初始化对象。

此外,考虑使用依赖注入框架(如Hilt)

💥 Activity初始化

活动创建通常需要大量高开销工作。 通常,有机会优化这项工作以实现性能改进。

产生的原因包括:

  • 加载大型或复杂的布局。
  • 阻止在磁盘或网络 I/O 上绘制屏幕。
  • 加载和解码Bitmap。
  • VectorDrawable 对象。
  • Activity 初始化任何全局单例对象。
  • 所有资源初始化。

解决方案如下。

🌀 布局优化

  • 通过减少冗余或嵌套布局来扁平化视图层次结构。
  • 布局复用(< include/>和 < merge/> )
  • 使用ViewStub,不加载在启动期间不需要可见的 UI 部分。

🌀 代码优化

  • 不必要的初始化还是磁盘I/O,延迟初始化
  • 资源初始化分类,以便应用程序可以在不同的线程上延迟执行。
  • 动态加载资源和Bitmap

关于这两块的优化后续会有单独的文章去写。

🔥 阻塞实验

💥 Application 阻塞 2秒, Activity 阻塞 2秒

🌀 SccApp.class

public class SccApp extends Application {
    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    public void onCreate() {
        super.onCreate();
        String name = getProcessName();
        MLog.e("ProcessName:"+name);
        getProcessName("com.scc.demo");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

🌀 MainActivity.class

public  class MainActivity extends ActivityBase implements View.OnClickListener {
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e(this.getClass().getName(), "onCreate");
        setContentView(R.layout.activity_main);
        ...
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                    reportFullyDrawn();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

报告的日志,如下:

//冷启动
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +5s458ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +8s121ms
//温启动(进程被杀死)
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +5s227ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +7s935ms
//热启动
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +2s304ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +5s189ms
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +2s322ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +5s169ms

💥 将Appliacation 和Activity阻塞的2秒都放在工作线程去操作

这个就是把代码放在如下代码中执行即可,就不全部贴出来了。

        new Thread(new Runnable() {
            @Override
            public void run() {
                ...
            }
        }).start();

运行结果如下:

//冷启动
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +1s227ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s957ms
//温启动(进程被杀死)
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +1s83ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s828ms
//热启动
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +324ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s169ms
I/ActivityTaskManager: Displayed com.scc.demo/.actvitiy.MainActivity: +358ms
I/ActivityTaskManager: Fully drawn com.scc.demo/.actvitiy.MainActivity: +3s207ms

🔥 APP 启动黑/白屏

Android 应用启动时,尤其是大型应用, 经常出现几秒钟的黑屏或白屏,黑屏或白屏取决于主界面 Activity 的主题风格。

💥 优雅的解决黑白屛

Android 应用启动时很多大型应用都会有一个广告(图片及视频)页或闪屏页(2-3S)。这并不是开发者想要放上去的,而是为了避免上述启动白屏导致用户体很差。当然你可以珍惜这2-3秒做一个异步加载或者请求。

写到这里。应用启动模式、启动时间、启动速度优化算是完事了。当然后面如果有更好的优化方案还会继续补充。

到此这篇关于Android 勇闯高阶性能优化之启动优化篇的文章就介绍到这了,更多相关Android 启动优化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android图片性能优化详解

    1. 图片的格式 目前移动端Android平台原生支持的图片格式主要有:JPEG.PNG.GIF.BMP.和WebP(自从Android 4.0开始支持),但是在Android应用开发中能够使用的编解码格式只有三种:JPEG.PNG.WebP,图片格式可以通过查看Bitmap类的CompressFormat枚举值来确定. public static enum CompressFormat { JPEG. PNG. WebP; private CompressFormat() { } } 如果要在

  • 浅谈Android性能优化之内存优化

    1.Android内存管理机制 1.1 Java内存分配模型 先上一张JVM将内存划分区域的图 程序计数器:存储当前线程执行目标方法执行到第几行. 栈内存:Java栈中存放的是一个个栈帧,每个栈帧对应一个被调用的方法.栈帧包括局部标量表, 操作数栈. 本地方法栈:本地方法栈主要是为执行本地方法服务的.而Java栈是为执行Java方法服务的. 方法区:该区域被线程共享.主要存储每个类的信息(类名,方法信息,字段信息等).静态变量,常量,以及编译器编译后的代码等. 堆:Java中的堆是被线程共享的,

  • 简单了解Android性能优化方向及相关工具

    开发一款性能优良的应用是每一个Android开发者都必须经历的挑战.在移动端资源有限的前提下,提高应用的性能显得尤为重要.常见的提高APP性能的优化方向有三个:布局和渲染优化.内存优化.功耗优化. 一:布局优化 所谓布局优化,就是尽量减少布局的嵌套层级,减少无用的布局.主要的优化方法有: (1)优先使用RelativeLayout来减少布局嵌套层数,否则尽量使用LinearLayout.这是因为RelativeLayout能够在不嵌套的情况下完成复杂的布局,而当布局比较简单时优先使用Linear

  • 详解Android性能优化之启动优化

    1.为什么要进行启动优化 网上流行一种说法,就是8秒定律,意思是说,如果用户在打开一个页面,在8秒的时间内还没有打开,那么用户大概的会放弃掉,意味着一个用户的流失.从这里就可以看出,启动优化的重要性了. 2.启动的分类 2.1 冷启动 先来看看冷启动的流程图 从图中可以看出,APP启动的过程是:ActivityManagerProxy 通过IPC来调用AMS(ActivityManagerService),AMS通过IPC启动一个APP进程,ApplicationThread通过反射来创建App

  • Android APP性能优化分析

    本文通过Android APP性能优化的四个方面做了详细分析,并对原理和重点做了详细解释,以下是全部内容: 说到 Android 系统手机,大部分人的印象是用了一段时间就变得有点卡顿,有些程序在运行期间莫名其妙的出现崩溃,打开系统文件夹一看,发现多了很多文件,然后用手机管家 APP 不断地进行清理优化 ,才感觉运行速度稍微提高了点,就算手机在各种性能跑分软件面前分数遥遥领先,还是感觉无论有多大的内存空间都远远不够用.相信每个使用 Android 系统的用户都有过以上类似经历,确实,Android

  • Android性能优化之Bitmap图片优化详解

    前言 在Android开发过程中,Bitmap往往会给开发者带来一些困扰,因为对Bitmap操作不慎,就容易造成OOM(Java.lang.OutofMemoryError - 内存溢出),本篇博客,我们将一起探讨Bitmap的性能优化. 为什么Bitmap会导致OOM? 1.每个机型在编译ROM时都设置了一个应用堆内存VM值上限dalvik.vm.heapgrowthlimit,用来限定每个应用可用的最大内存,超出这个最大值将会报OOM.这个阀值,一般根据手机屏幕dpi大小递增,dpi越小的手

  • 浅谈android性能优化之启动过程(冷启动和热启动)

    本文介绍了浅谈android性能优化之启动过程(冷启动和热启动) ,分享给大家,具体如下: 一.应用的启动方式 通常来说,启动方式分为两种:冷启动和热启动. 1.冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就是冷启动. 2.热启动:当启动应用时,后台已有该应用的进程(例:按back键.home键,应用虽然会退出,但是该应用的进程是依然会保留在后台,可进入任务列表查看),所以在已有进程的情况下,这种启动会从已有的进程中来启动应用,这个方式叫热

  • Android高级开发之性能优化典范

    本章介绍android高级开发中,对于性能方面的处理.主要包括电量,视图,内存三个性能方面的知识点. 1.视图性能 (1)Overdraw简介 Overdraw就是过度绘制,是指在一帧的时间内(16.67ms)像素被绘制了多次,理论上一个像素每次只绘制一次是最优的,但是由于重叠的布 局导致一些像素会被多次绘制,而每次绘制都会对应到CPU的一组绘图命令和GPU的一些操作,当这个操作耗时超过16.67ms时,就会出现掉帧现象,表现为应用卡顿,所以对重叠不可见元素的重复绘制会产生额外的开销,需要尽量减

  • Android项目实战教程之高仿网易云音乐启动页实例代码

    前言 本文主要给大家介绍了关于Android高仿网易云音乐启动页的相关内容,这一节我们来讲解启动界面,效果如下: 首次创建一个SplashActivity用来做启动界面,因为创建完项目默认是MainActivity做主界面,所以需要去掉,将启动配置到同时去掉SplashActivity,并且去掉SplashActivity的标题栏,同时还要设置为全屏. Activity启动配置 在清单文件将启动配置剪贴到SplashActivity: <activity android:name=".ac

  • Android 分析实现性能优化之启动速度优化

    目录 启动方式 冷启动(启动优化目标) 热启动 温启动 启动流程中可优化的环节 检测工具 启动时间检测 Logcat Displayed adb 命令统计 CPU profile API level >= 26 API level < 26 StrictMode 严苛模式 优化点 黑白屏问题 本文主要探讨以下几个问题: 启动方式 启动流程中可优化的环节 检测工具 优化点 黑白屏问题 启动方式 应用有三种启动状态,每种状态都会影响应用向用户显示所需的时间:冷启动.温启动与热启动 冷启动(启动优化

  • Android中方法数超限问题与启动优化详解

    前言 最近写了篇有关Eclipse工程转Android Studio工程的文章,而导致公司项目需要转 AS 的直接原因,就是今天要写的主题–方法数超限,相信大多数 Android 项目的都会碰到这个问题. 传统的 Eclipse 解决方法数超限的办法,就是在 project.properties 中加上 dex.force.jumbo=true ,然后清理工程重新编译.但是,当方法数越来越多,这个方法也会解决不了问题,这个时候,就要用到 Google 官方给出的方案 MultiDex了. Mul

  • Android优化之启动页去黑屏实现秒启动

    前言 还记得之前我们写了一篇文章,基于RxJava实现酷炫启动页,然而当我们点击桌面图标启动APP时,有时会闪一下黑色背景,有时黑色背景时间还比较长,哎呀,难看死了,这个怎么办捏,别方,我们今天就来看看启动页的优化. 一.消除启动时的黑屏 点击桌面launcher图标启动APP,闪现的黑色背景其实是出现在我们看到界面第一帧之前.那我们就要想办法让这个黑色的背景变成用户喜欢看到的画面或者让它透明化.有了思路方法也就粗现了,我们有下面两种方案: 自定义WelcomActivity的Theme 说白了

随机推荐