Android - 启动白屏分析与优化

记录一次项目开发中的一个小问题,最近发现公司的项目启动白屏的时间非常长久,在高端机也要2-3秒,那么在低端机岂不是更久,别人打开你的APP,发现一篇白或者一片黑,很不友好,不懂的人还以为开发者很水。
先上一张我项目的启动时间


原始时间图.png

其实我的东西也不多,要3秒钟。所以App启动的时候会出现白屏(黑屏),非常不友好。网上有一种解决方案比较多人知道.就是将主题(白色/黑色)设置成自己SplashActivity的效果一样的话。用户误以为白屏就是正在启动的启动页,但是这种做法实际上并不能减少App启动的时间,只是将白屏的时候换上了一个跟启动页一样的背景。下面我讲两种做法。

下面跟大家科普一下启动模式。听到启动模式,大家会想到4大启动模式 ?相信Activity的启动模式大家复习基础知识面试的时候已经背烂了,我今天讲的不是Activity的启动模式,而是应用的启动模式。

应用的启动方式

1、冷启动:系统的进程没有,直到此开始,创建了应用程序的进程。 在应用程序自设备启动以来第一次启动或系统杀死应用程序等情况下会发生冷启动。 这种类型的启动在最小化启动时间方面是最大的挑战,因为系统和应用程序比其他启动状态具有更多的工作。

2、热启动:与冷启动相比,热启动应用程序要简单得多,开销更低。在热启动,所有的系统都是把你的活动到前台。如果所有应用程序的活动仍驻留在内存中,那么应用程序可以避免重复对象初始化,UI的布局和渲染。
热启动显示与冷启动场景相同的屏幕行为:系统进程显示空白屏幕,直到应用程序完成呈现活动。

3、温启动:用户退出您的应用,但随后重新启动。该过程可能已继续运行,但应用程序必须通过调用onCreate()从头开始重新创建活动。系统从内存中驱逐您的应用程序,然后用户重新启动它。进程和Activity需要重新启动,但任务可以从保存的实例状态包传递到onCreate()中。

为什么出现白屏

Application的构造器方法——>attachBaseContext()——>onCreate()——>Activity的构造方法——>onCreate()——>配置主题中背景等属性——>onStart()——>onResume()——>测量布局绘制显示在界面上。
从你点击桌面的图标开始安卓系统会从Zygote进程中fork创建出一个新的进程分配给该应用,之后会依次创建和初始化Application类。当这些操作走完之后,你才能看到SplashActivity的第一眼。那么这期间你Application里onCreate做了N多的SDK的初始化,这段时间您的屏幕都是你手机默认主题的颜色(白色/黑色)。这就是为什么我们做的APP会出现白屏。

优化方案

解决方案一 修改启动Activity的主题

步骤一 styles.xml 添加Style

 <style name="SplashTheme" parent="AppTheme">
        <!-- 将splash图片设置在这,这样这张图片取代白屏 -->
        <item name="android:windowBackground">@drawable/bg_splash</item>
        <item name="android:windowTranslucentStatus">true</item>
        <item name="android:windowTranslucentNavigation">true</item>
 </style>

步骤二 AndroidManifest.xml 添加启动页主题

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

解决方案二

既然是Application里做了很多耗时的初始化导致启动耗时,那么我们可以试着优化一下这里的初始化。介绍一样东西 :IntentService 。Service大家应该会比较熟悉,那我简单的科普一下这个类。

IntentService

IntentService is a base class for Service that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
This “work queue processor” pattern is commonly used to offload tasks from an application’s main thread. The IntentService class exists to simplify this pattern and take care of the mechanics. To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.
All requests are handled on a single worker thread – they may take as long as necessary (and will not block the application’s main loop), but only one request will be processed at a time.
IntentService是Service的子类,根据需要处理异步请求(以intent表示)。客户端通过调用startService(Intent) 发送请求,该Service根据需要启动,使用工作线程处理依次每个Intent,并在停止工作时停止自身。
这种“工作队列处理器”模式通常用于从应用程序的主线程中卸载任务。 IntentService类的存在是为了简化这种模式。 要使用它,扩展IntentService并实现onHandleIntent(Intent)。 IntentService将收到Intents,启动一个工作线程,并根据需要停止该服务。
所有请求都在单个工作线程处理 - 它们可能需要很长的时间(并且不会阻止应用程序的主循环),但是一次只会处理一个请求。

IntentService与Service的区别

Android中的Service是用于后台服务的,当应用程序被挂到后台的时候,问了保证应用某些组件仍然可以工作而引入了Service这个概念,那么这里面要强调的是Service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,也就是说,在更多时候不建议在Service中编写耗时的逻辑和操作,否则会引起ANR。

那么我们当我们编写的耗时逻辑,不得不被service来管理的时候,就需要引入IntentService,IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期,那么与service不同的是,IntentService在执行onCreate操作的时候,内部开了一个线程,去你执行你的耗时操作。

上面纯粹帮你们百度了一波,其实我也不是很懂,直接上代码吧。

InitIntentService.java

import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.Nullable;

/**
 * Created by 卖火柴的小女孩 - Jc on 2018/8/8.
 */

public class InitIntentService extends IntentService {

    private static final String ACTION_INIT = "com.hjc.helloworld.action.INIT";

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     */
    public InitIntentService() {
        super("InitIntentService");
    }

    public static void start(Context context) {
        Intent intent = new Intent(context, InitIntentService.class);
        intent.setAction(ACTION_INIT);
        context.startService(intent);
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        if (intent != null && ACTION_INIT.equals(intent.getAction()))
        {
            //执行百度地图初始化
            //Push初始化
            //友盟初始化
            //....N多第三方初始化
        }
    }
}

App.java


import android.app.Application;

/**
 * Created by 卖火柴的小女孩 - Jc on 2018/8/8.
 */

public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        InitIntentService.start(this);
    }
}

AndroidManifest.xml

<service  android:name=".InitIntentService"/>

其实你可以理解开辟了另一个空间去执行各种第三方启动的耗时操作。看完本文的小伙伴,结合解决方案一和解决方案二,理论上能很大的解决APP启动白屏的问题了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • 本文出自 Eddy Wiki ,转载请注明出处:http://eddy.wiki/interview-androi...
    eddy_wiki阅读 3,252评论 0 20
  • 2.1 Activity 2.1.1 Activity的生命周期全面分析 典型情况下的生命周期:在用户参与的情况下...
    AndroidMaster阅读 3,018评论 0 8
  • 【Android Service】 Service 简介(★★★) 很多情况下,一些与用户很少需要产生交互的应用程...
    Rtia阅读 3,137评论 1 21
  • 1.什么是Activity?问的不太多,说点有深度的 四大组件之一,一般的,一个用户交互界面对应一个activit...
    JoonyLee阅读 5,724评论 2 51
  • 这件事发生距离现在大概有30多天了吧,我实在撑不住,打算把它写出来,也许你们不会相信,甚至是我自己都觉得是在做梦,...
    咚咚咚咚咚咚阅读 581评论 2 12