性能优化(一)APP 启动优化(不敢说秒开,可是最终优化完真不到 1s)

性能优化系列

APP 启动优化java

UI 绘制优化android

内存优化shell

图片压缩数据库

长图优化性能优化

电量优化网络

Dex 加解密app

动态替换 Application异步

APP 稳定性之热修复原理探索ide

APP 持续运行之进程保活实现函数

ProGuard 对代码和资源压缩

APK 极限压缩

简介

性能优化的目的不是为了优化而优化,并且为了之后再也不优化, 给本身统一 一个标准。

这里也许会有人问 APP 启动还须要优化吗?启动又不是咱们本身写的代码,难道 Google 工程师会犯这么低级的错吗?其实这还真不是 Google 的错,应该说是给咱们开发者留了一个坑吧。应该有的同窗知道是怎么一回事儿了,当咱们在系统桌面任意点击一个 APP 是否是会发现启动的时候有一瞬间有白屏出现(之前老版本是黑屏) 那么咱们怎么来优化这个黑白屏的问题勒,如今咱们先来了解一下 Android 手机重开机到启动 APP 的过程吧。

APP 启动流程

这里会设计到 Android 系统源码的知识,但并不会深刻解析源码,咱们只是了解一个过程,由于太深刻我本身也懵。

系统的启动

我在这里大体分为了 6 个步骤,下面以流程图为准

启动步骤

  1. 首先拿到一部 Android 系统的手机打开电源,引导芯片代码加载引导程序 BootLoader 到 RAM 中去执行。
  2. BootLoader 把操做系统拉起来。
  3. Linux 内核启动开始系统设置,找到一个 init.rc 文件启动初始化进程。
  4. init 进程初始化和启动属性服务,以后开启 Zygote 进程。
  5. Zygote 开始建立 JVM 并注册 JNI 方法,开启 SystemServer。
  6. 启动 Binder 线程池和 SystemServiceManager,并启动各类服务。

Launcher 启动

App Appcation 启动

  1. 手机回到系统桌面, 经过 adb shell dumpsys window w |findstr / |findstr name= 来查看当前的进程和 Activity 名。

  2. 当点击桌面 APP 图标的时候会走 Launcher . java 的 onClick (View view) 方法,详细见下图。

    startActivity(intent) 会开启一个 APP 进程

  3. AcitivityThread main() 调用执行流程,见下图。

    最后 ActivityThread main() 是经过反射来进行初始化的

  4. ActivityThread.java 作为入口,详细解说 main() 函数,仍是以一个动画来演示一下吧;

    根据上面的动画,你们应该已经明白 ActivityThread.java main() 方法中 Appcation onCreate() 的是怎么被调用起来的吧。

    注意:

    不知道你们有没有注意 ActivityThread main() 中 Looper.prepareMainLooper(); 其实我们为何可以在 Main Thread 中建立 Handler 不会报错了吧,是由于 Activity 启动的时候在这里已经默认开启了 Looper。

APP 启动黑白屏问题

终于到了正题了,下面咱们就来讲下启动黑白屏的问题,仍是先来看一个 GIF 吧。

市面上 APP 黑白屏

​ 从上面的一段录屏咱们能够发现市面上常见的 APP 启动有的是白屏有的是作了优化。黑屏只有在 Android 4.n 具体是哪一个版本我也忘了。那么如今咱们就以我如今的真实项目来优化一下启动。

真实项目中优化

简介

首先为何会形成白屏勒咱们来看一段源码

最后就是这个 windowBackground 搞的鬼,知道了是这个搞的鬼那么咱们就能够来进行优化了。

优化方案 一

在本身的 AppTheme 中加入 windowBackground 
复制代码

优化方案 二

设置 windowbackgroud 为透明的

<item name="android:windowIsTranslucent">true</item>
复制代码

可是:

​ 这 2 中方法会有一个问题,就是全部的 Activity 启动都会显示。

优化方案 三

  1. 单独作成一个 AppTheme.Launcher
<style name="AppTheme.Launcher">
        <item name="android:windowFullscreen">true</item>
        <!--<item name="android:windowDisablePreview">true</item>-->
        <item name="android:windowBackground">@color/colorAccent</item>
    </style>
复制代码
  1. 在清单文件中 启动 Activity 加入该 主题

    <activity
                android:name="com.t01.android.dida_login.mvp.ui.activity.LoginActivity"
                android:configChanges="keyboardHidden|orientation|screenSize"
                android:theme="@style/AppTheme.Launcher"
                android:windowSoftInputMode="adjustUnspecified|stateHidden">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    复制代码
  2. 在启动 Activity 页面中加入

    setTheme(R.style.AppTheme_Launcher);
    复制代码

最后这样作只有启动的 UI 才能见到本身的样式

  1. 最后效果,由于我这里没有背景图,故弄了一个主题颜色,若是想要设置一张背景图片能够参考下面的示例,否则有可能会引发图片拉伸效果。

    我这里启动时间大概在 500 ms ~ 800 ms 左右。

    <?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item>
            <bitmap android:src="@mipmap/app_bg"
                android:gravity="fill"/>
        </item>
    </layer-list>
    复制代码

    最后在清单 启动 Activity 的 Theme 中修改成

    <item name="android:windowBackground">@drawable/app_theme_bg</item>
    复制代码
  2. 听说 QQ 的实现方法是(这里只作参考,感兴趣的同窗能够本身试试。)

    <item name="android:windowDisablePreview">true</item>
     <item name="android:windowBackground">@null</item>
    复制代码

启动时间查看

4.4 之前版本查看

adb shell am start -W packName/activity 全路径
复制代码

4.4 版本之后查看方式

经过关键字 Displayed 并筛选为 No Filters

2019-04-25 18:35:57.629 508-629/? I/ActivityManager: Displayed com.lingyi.autiovideo.lykj/com.t01.android.dida_login.mvp.ui.activity.LoginActivity: +844ms
复制代码

工具分析代码执行

Appcation 中查看耗时经过(若是有的同窗还用 Log 打印系统时间来相减来查看 耗时的话,看完我这篇文章就能够换成下面方法了,否则就有点 LOW 了哈)

//开始计时
Debug.startMethodTracing(filePath);
     中间为须要统计执行时间的代码
//中止计时
Debug.stopMethodTracing();
复制代码

仍是经过一组动画来看我怎么操做的吧。(注意这里的时间是 微妙 微妙/10^6 = s 应该是这样,忘了)

这个工具能够很友好的提示每一个函数具体在内部执行了多少时间,卡顿其实也能够用这个方法来进行监测

导出 trace 文件命令

adb pull /storage/emulated/0/appcation_launcher_time.trace
复制代码

我这里耗时还不算太大 大概在 0.2 - 0.3 s 左右。

Appcation 中优化方案(并不绝对,优化思路差很少)

  1. 开子线程
    • 线程中没有建立 Handler、没有操做 UI 、对异步要求不高
  2. 懒加载
    • 用到的时候在初始化,如网络,数据库,图片库,或一些三方库。
  3. 使用 IntentService onHandleIntent () 方法来进行初始化一些比较耗时的操做

总结

最后启动优化能够配合上面的 3 点优化方案 + Appcation 优化方案 = 你本身最优方案。