Android性能优化—— 黑白屏启动优化

概述

我们在很多APP启动的时候都能看到一闪而过的黑屏或者白屏,在我们这些强迫症深度患者看来,确确实实是个很糟糕的体验。但是在我们打开QQ或者一些优化过的应用的时候却看不到所谓的黑屏或白屏。我们今天就来探讨下这个黑白屏启动优化

历史

在最早的Android机器上, 点击需要一定的时间来响应,然后启动。但是在这 App 未完全启动的时候,用户不能明确 App 是否已经启动,为了解决这个用户体验的问题,特意加上了启动黑白屏来表示 App 已经启动。

但是解决了点击无反应的问题,又出现了黑白屏体验不好的问题,方法总比问题多,有的应用设置背景为透明,有的应用放置图片,总之各有妙招

黑白屏出现原因

当我们设置下面主题属性时,会出现首次启动白屏或者黑屏的问题

白屏    <style name="AppTheme" parent="Theme.AppCompat.Light">
黑屏    <style name="AppTheme">(在以前的老版本上有效,现在的版本默认使用透明处理了)

我们点击Theme.AppCompat.Light一直追溯,找到一个父类name="Platform.AppCompat.Light"中定义了
<item name="android:windowBackground">用来控制黑白屏,我们能从下面图中看到windowBackground被设置为@color/background_material_light

在这里插入图片描述

当从launcher启动一个APP时,需要fork一个进程并进行一些初始化,而fork进程和初始化是需要时间的,这时候就有了StartingWindow(也称之为PreviewWindow)的出现,

StartingWindow一般出现在应用程序进程创建并初始化成功前,所以它是个临时窗口,对应的WindowTypeTYPE_APPLICATION_STARTING。目的是告诉用户,系统已经接受到操作,正在响应,在程序初始化完成后实现目的UI,同时移除这个窗口

我们看到windowBackground这个属性设置的值就是为这个StartingWindow服务的,设置黑屏主题就会显示黑屏,设置白屏主题就会显示白屏,设置一张图片就会显示一张图片

Android系统架构

我们作为上层开发者,理解Android架构便于我们更好的优化我们的应用,下面开始我们的性能优化之路

​ 像Android开源和兼容性技术负责人Dan Morrill在Android开发手册兼容性部分所解释的,“Android并不是传统的Linux风格的一个规范或分发版本,也不是一系列可重用的组件集成,Android是一个用于连接设备的软件块。如果在真个Android系统生态来看的话,我们设计编写的应用只是作为上层的展示,仅仅是整个生态中最表面的一块,用一个通俗的说法就是应用只是一个我们成为的APK的压缩文件,他大体内容页如下图所示

Android系统架构图
在这里插入图片描述

​ Android是基于Linux的一个操作系统,它可以分为五层,下面是它的层次架构图,可以记一下,因为后面应该会总结到SystemServer这些Application Framework层的东西

在这里插入图片描述

App启动流程

下面该图是阿里公众号里找的一个图,大致描述了Android系统的启动流程,图上标识的数字跟下面的介绍没有关系,仅供参考
在这里插入图片描述

下面详细介绍具体启动流程

  1. 打开电源 引导芯片代码加载引导程序Boot Loader到RAM中去执行

  2. BootLoader把操作系统拉起来

  3. Linux 内核启动开始系统设置,找到一个init.rc文件启动初始化进程

  4. init进程初始化和启动属性服务,之后开启Zygote进程

  5. Zygote开始创建JVM并注册JNI方法,开启SystemServer

  6. 启动Binder线程沲和SystemServiceManager,并启动各种服务

  7. AMS启动Launcher

Zygote 进程

​ Zygote 的中文意思是受精卵,从这个意思里也可以看出 Zygote 进程是用来分裂复制(fork)的,实际上所有的 App 进程都是通过对 Zygote 进程的 Fork 得来的。Zygote 会在其启动后,预加载必要的 Java Classes 和 Resources,并启动 System Server ,并打开 /dev/socket/zygote socket 去监听启动应用程序的请求

​ Android进程与Linux进程一样. 默认情况下, 每个apk运行在自己的Linux进程中. 另外, 默认一个进程里面只有一个线程—主线程. 这个主线程中有一个Looper实例, 通过调用Looper.loop()从Message队列里面取出Message来做相应的处理,就是我们常说的Handlder原理

Launcher应用启动

我们从系统源码 packages\apps\Launcher2\src\com\android\launcher2\目录下可以找到Launcher.java文件,当我们用手点击一个图标时,就到了这个类执行onClick(View view)方法,会把这个应用的相关信息传入

获取一个intent

-->startActivitySafely(v, intent, tag)

–>startActivity(v, intent, tag);–>startActivity(intent);

startActivity(intent)会开一个APP进程

ActivityThread.java做为入口

这里是Launcher点击应用图标的入口

在这里插入图片描述
这里放个startActivitySafely方法的源码

在这里插入图片描述

下面是大神老师神级画作

在这里插入图片描述
下面给出一个好看一点的图

在这里插入图片描述

app白屏和黑屏的一般解决方案

  1. 在自己的<style name="AppTheme" parent="Theme.AppCompat.Light">中加入windowsbackground,这样,在App启动的时候就会直接弹出设置的背景

在这里插入图片描述

  1. 设置windowbackground为透明的 <item name="android:windowIsTranslucent">true</item>

前面两种方法都有一个问题,就是在所有Activity启动的时候都会先显示这个默认的图片,如果是透明的话会出现点了图标没反映的情况

  1. 单独制作一个主题

    <style name="AppTheme.Launcher">
            <item name="android:windowBackground">@drawable/bg</item>
        </style>
        <style name="AppTheme.Launcher1">
            <item name="android:windowBackground">@drawable/bg</item>
        </style>
        <style name="AppTheme.Launcher2">
            <item name="android:windowBackground">@drawable/bg</item>
        </style>
    

    然后在Menifest中相应的Activity下设置

    <activity android:theme="@style/AppTheme.Launcher"
    

    然后在程序中使用

    setTheme(R.style.AppTheme);
    

    让APP中所有的activity还是使用以前的样式,这样做就只有启动时才使用自己的样式

  2. 介绍下qq中方式,在style中设置下面的属性

    关闭预显示
    <item name="android:windowDisablePreview">true</item> 
    背景设置为空
    <item name="android:windowBackground">@null</item>
    

    qq比较牛逼的一点是他在Application中不初始化任何的东西,将启动时间优化到极致,下面会讲到具体的方法

  3. 其实大多数应用不需要做到像qq那样启动速度快到极致,像腾讯系、阿里系的一些应用都是只显示一张图片,然后开始显示一个3秒左右的广告,在显示广告的时间里进行一些初始化

Trace工具分析代码执行时间

黑白屏的优化只是表面上的优化,只是做到让用户觉得启动速度很快,但实际启动速度一点都没变,下面就该介绍真正的启动优化

工欲善其事,必先利器其器,google小姐已经为我们准备好了工具

Debug.startMethodTracing(filePath);
中间为需要统计执行时间的代码
Debug.stopMethodTracing();

或者直接使用Android Device file Explorer导出的文件

adb pull /storage/emulated/0/app1.trace把文件拉出来分析
把pull到电脑上的文件拖到AS中就可以分析了

查看页面启动时间

sdk版本4.4以前

通过命令

 adb shell am start -W com.lqr.wechat/com.lqr.wechat.activity.SplashActivity

可以查看页面的启动时间

ThisTime:最后一个启动的Activity的启动耗时;
TotalTime:自己的所有Activity的启动耗时;
WaitTime: ActivityManagerService启动App的Activity时的总时间(包括当前Activity的onPause()和自己Activity的启动)。

AM.java在系统源码中的路径

frameworks\base\cmds\am\src\com\android\commands\am

APP启动时间优化

优化方案:

1.开线程

​ 内部没有创建handler 没有操作UI的事件 对异步要求不高

2.懒加载

用到的时候再初始化,如网络,数据库操作

引用文章

  1. Google工程师多图详解Android系统架构 https://yq.aliyun.com/articles/301672

  2. Android启动流程 、app安装和启动原理 https://www.jianshu.com/p/12de32b31836

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ddssingsong

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

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

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

打赏作者

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

抵扣说明:

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

余额充值