美文网首页
APP 优化 - app 启动优化

APP 优化 - app 启动优化

作者: 前行的乌龟 | 来源:发表于2018-11-09 05:25 被阅读246次

大家都遇到过自己 app 启动时间有些长,屏幕白屏的问题吧。一个正常的商业 app 在启动时时会加载一大票组件的初始化的,功能越多需要加载的组件越多,那么 app 启动的时间就越长,app 白屏或黑屏的时间也越长,怎么办呀,今天就来优化一下,谈谈思路,不涉及过多代码

下面是几个 app 启动优化可供参考的案例:


app 启动方式

1、冷启动
App没有启动过或App进程被killed, 系统中不存在该App进程。需要创建App进程, 加载相关资源, 启动Main Thread, 初始化首屏Activity等。在这个过程中, 屏幕会显示一个空白的窗口(颜色基于主题), 直至首屏Activity完全启动。

2、热启动
热启动意味着你的App进程只是处于后台, 系统只是将其从后台带到前台, 展示给用户。在这个过程中, 屏幕会显示一个空白的窗口(颜色基于主题), 直至activity渲染完毕。

3、温启动
介于冷启动和热启动之间, 一般来说在以下两种情况下发生:

用户back退出了App, 然后又启动. App进程可能还在运行, 但是activity需要重建
用户退出App后, 系统可能由于内存原因将App杀死, 进程和activity都需要重启
启动优化主要是针对冷启动. 热启动和温启动都相对较快。

2206304-b6fe84c9f4b8284e.png

关于 StartingWindow 的解释

StartingWindow 我也是才刚刚看到大家说的, 之前一直在此处有疑虑额,但是一直没搞明白,其实就是在 app 在冷启动时先显示一个空白的 window 给大家看,这个 window 叫做 StartingWindow

不错的解释:

application以及activity初始化是一个相当复杂的过程,而白屏或者黑屏恰恰就是这个过程的产物:在应用程序刚启动到应用程序初始化完全之间有一段时间空隙,这时候系统创建了一个空白窗口,叫StartingWindow。这个窗口让人感觉activity已经启动了只是没填充好数据。它是个临时窗口,对应的WindowType是TYPE_APPLICATION_STARTING。这个空白窗口是为了告诉用户,系统已经接受到操作,正在响应。应用程序初始化完成加载完第一帧之后,这个窗口就会被移除。

Window的顶层是DecorView,所以StartingWindow显示一个空DecorView,但是会给这个DecorView应用 launch activity指定的Theme,如果 launch activity没有指定Theme就用application的。activity启动时,windowBackground比setContentView()要先加载,这一段时间如果Theme是Light,屏幕就是白色的;如果是Dark,就会显示黑屏。上述就是黑白屏的原因了


1. 一个正常的 app 启动我们都这么干吧

友盟统计,推送,地图,IM,自家的各种组件,这些很耗时的,尤其是第三方组件

魅族工程师统计过,若是 app 启动时间超过 400 毫秒,那么用户在桌面点击你的应用图标后,将感觉到明显的卡顿

2. app 启动的过程

app 的过程是怎么样的,这 400 毫秒都包含哪些生命周期函数呢~,这里不做深入展开,仅仅看看 app 启动涉及到的生命周期函数及其顺序

  • 点击桌面图标后,安卓系统会 fork 创建出一个新的进程分配给该应用,之后会依次创建和初始化Application类。当这些操作走完之后,你才能看到 SplashActivity 的第一眼。

  • Application ——>attachBaseContext()——>onCreate()——>Activity——>onCreate()——>配置主题中背景等属性——>onStart()——>onResume()——>测量布局绘制显示在界面上

那么在这期间,我们若是在 Application 的 onCreate 做了太多的 SDK的初始化的话,这段时间您的屏幕都是你手机默认主题的颜色(白色/黑色),这就是为什么我们做的APP会出现白屏

3. 那怎么优化呢

优化思路主要有2个:

  • 把 Application 的 onCreate 中的初始化操作尽量都放在非 UI 线程,这样不会卡 UI ,大众做法是启动一个 IntentService
  • 并不是所有的初始化操作都可以放到 非 UI 线程的,并且系统本身也是很耗时的,若是不想让用户看白屏,那么可以给 app 设置一个背景,先让用户看启动图,产生一个 app 已经启动的假象

关于分割各个组件初始化方法方案看这个,有的必须在 application,其次的放 splashActivity,最后没什么影响的异步线程

4. 如何给 app 设置背景

这里思路也有3个:

  • 给 application 的 theme 设置 windowBackground
  • 给 SplashActivity 的 theme 设置 windowBackground
  • 给 SplashActivity 加透明背景,这样在 app 启动时会透明,就跟没启动一样,一直到后面我们改的 activity 的 theme 加载出来

这里推荐第二种方法,因为 application 的 theme 设置是全局所有 Activity 都有效的,若是 给 application 的 theme 设置 windowBackground 后,所有的 Activity windowBackground 都会设置成这样,这会造成过度绘制的问题,另外这种效果也不是我们想要的

那么给 SplashActivity 的 theme 设置 windowBackground 就成了我们的选择,为啥呢,因为 app 启动时 ,为了不让我们看大黑屏会默认启动一个空内容的 window 先显示着,这个 window 的背景就是 application theme 的 windowBackground ,若是没有的话就用 SplashActivity theme 的 windowBackground

这个体验才是最好的,经测试 4.X 版本也没问题,这里我们在 application 的 onCreate 里延迟3秒,并且给 SplashActivity theme 设置 windowBackground,然后我们看看效果如何

application 设置:

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()

            Thread.sleep(3000)
    }
}

theme 设置:

        <style name="SplashTheme" parent="AppTheme">
            <item name="android:windowBackground">@drawable/ic_dog</item>
        </style>

        <activity
            android:name=".MainActivity" android:theme="@style/SplashTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

效果:


录的不是很好,大家见谅,狗狗还是很可爱的~,最后 view 显示的那一下,gif 没提现出来,大家脑补一下吧~

app 启动优化的思路基本上就是这样了,大家翻再多的资料也不会出这个圈了

然后有个流氓的,launch activity 透明背景,让用户以后还没启动呢,这样太流氓了,我不喜欢,据说微信即使这么干的,这样其实体验也不是非常好

对于首个加载的Activity,可以使用透明背景:可以减少application加载主题的消耗

<style name= "EmptyTheme">
   <item name="android:windowIsTranslucent">true</item>
  <item name="android:windowNoTitle">true</item>
</style>

然后,在onCreate第一行执行:setTheme(R.style.AppTheme);


5. 很有意思的拼启动图片

我们直接使用大图作为启动画面的话是会话不少内存的,要是图片简单的话可以使用 SVG 矢量图,或是不给启动页设置主图背景,而是添加一个 imageview 进来,完事手动回收资源,再 GC,这样可以尽可能节省内存资源

要知道 drawable 里面的静态 png 图片除非我们拿到其 bitmap 对象手动标记回收,否则系统会一直保持在内存中,对于频繁使用的小图来说这是一种优化,但是对于仅仅使用一次的大图来说这就不合了

但是呢今天看到了一个很有意思的做大,使用 layer-list + 小图 拼一个大图出来,这样也可以实现节约内存的目的

<style name="SplashTheme" parent="AppTheme">
        <item name="android:windowTranslucentStatus">true</item>
        <item name="android:windowBackground">@drawable/logo_splash</item>
    </style>

<!--@drawable/logo_splash文件-->
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 如果item下的 bitmap 没有设置 gravity ,再API 23 以下,会出错! -->
    <item
        android:drawable="@color/splashBg"
        android:gravity="fill" />

    <item android:gravity="top">
        <bitmap
            android:gravity="top"
            android:src="@drawable/splash_top" />
    </item>

    <item
        android:bottom="72dp"
        android:gravity="bottom|center_horizontal">
        <bitmap
            android:gravity="bottom"
            android:src="@drawable/splash_bottom" />
    </item>
</layer-list>

这里还有更多玩法哦,甚至还有启动页动画实现的,值得看

相关文章

网友评论

      本文标题:APP 优化 - app 启动优化

      本文链接:https://www.haomeiwen.com/subject/sfqnxqtx.html