記錄一次項(xiàng)目開發(fā)中的一個(gè)小問題代态,最近發(fā)現(xiàn)公司的項(xiàng)目啟動(dòng)白屏的時(shí)間非常長久,在高端機(jī)也要2-3秒疹吃,那么在低端機(jī)豈不是更久,別人打開你的APP蹦疑,發(fā)現(xiàn)一篇白或者一片黑,很不友好萨驶,不懂的人還以為開發(fā)者很水歉摧。
先上一張我項(xiàng)目的啟動(dòng)時(shí)間
其實(shí)我的東西也不多,要3秒鐘。所以App啟動(dòng)的時(shí)候會(huì)出現(xiàn)白屏(黑屏),非常不友好腔呜。網(wǎng)上有一種解決方案比較多人知道.就是將主題(白色/黑色)設(shè)置成自己SplashActivity的效果一樣的話叁温。用戶誤以為白屏就是正在啟動(dòng)的啟動(dòng)頁,但是這種做法實(shí)際上并不能減少App啟動(dòng)的時(shí)間,只是將白屏的時(shí)候換上了一個(gè)跟啟動(dòng)頁一樣的背景。下面我講兩種做法核畴。
下面跟大家科普一下啟動(dòng)模式膝但。聽到啟動(dòng)模式,大家會(huì)想到4大啟動(dòng)模式 ?相信Activity的啟動(dòng)模式大家復(fù)習(xí)基礎(chǔ)知識(shí)面試的時(shí)候已經(jīng)背爛了,我今天講的不是Activity的啟動(dòng)模式谤草,而是應(yīng)用的啟動(dòng)模式跟束。
應(yīng)用的啟動(dòng)方式
1、冷啟動(dòng):系統(tǒng)的進(jìn)程沒有丑孩,直到此開始冀宴,創(chuàng)建了應(yīng)用程序的進(jìn)程。 在應(yīng)用程序自設(shè)備啟動(dòng)以來第一次啟動(dòng)或系統(tǒng)殺死應(yīng)用程序等情況下會(huì)發(fā)生冷啟動(dòng)温学。 這種類型的啟動(dòng)在最小化啟動(dòng)時(shí)間方面是最大的挑戰(zhàn)略贮,因?yàn)橄到y(tǒng)和應(yīng)用程序比其他啟動(dòng)狀態(tài)具有更多的工作。
2仗岖、熱啟動(dòng):與冷啟動(dòng)相比逃延,熱啟動(dòng)應(yīng)用程序要簡(jiǎn)單得多,開銷更低箩帚。在熱啟動(dòng)真友,所有的系統(tǒng)都是把你的活動(dòng)到前臺(tái)。如果所有應(yīng)用程序的活動(dòng)仍駐留在內(nèi)存中紧帕,那么應(yīng)用程序可以避免重復(fù)對(duì)象初始化盔然,UI的布局和渲染。
熱啟動(dòng)顯示與冷啟動(dòng)場(chǎng)景相同的屏幕行為:系統(tǒng)進(jìn)程顯示空白屏幕是嗜,直到應(yīng)用程序完成呈現(xiàn)活動(dòng)愈案。
3、溫啟動(dòng):用戶退出您的應(yīng)用鹅搪,但隨后重新啟動(dòng)站绪。該過程可能已繼續(xù)運(yùn)行,但應(yīng)用程序必須通過調(diào)用onCreate()從頭開始重新創(chuàng)建活動(dòng)丽柿。系統(tǒng)從內(nèi)存中驅(qū)逐您的應(yīng)用程序恢准,然后用戶重新啟動(dòng)它魂挂。進(jìn)程和Activity需要重新啟動(dòng),但任務(wù)可以從保存的實(shí)例狀態(tài)包傳遞到onCreate()中馁筐。
為什么出現(xiàn)白屏
Application的構(gòu)造器方法——>attachBaseContext()——>onCreate()——>Activity的構(gòu)造方法——>onCreate()——>配置主題中背景等屬性——>onStart()——>onResume()——>測(cè)量布局繪制顯示在界面上涂召。
從你點(diǎn)擊桌面的圖標(biāo)開始安卓系統(tǒng)會(huì)從Zygote進(jìn)程中fork創(chuàng)建出一個(gè)新的進(jìn)程分配給該應(yīng)用,之后會(huì)依次創(chuàng)建和初始化Application類敏沉。當(dāng)這些操作走完之后,你才能看到SplashActivity的第一眼果正。那么這期間你Application里onCreate做了N多的SDK的初始化,這段時(shí)間您的屏幕都是你手機(jī)默認(rèn)主題的顏色(白色/黑色)盟迟。這就是為什么我們做的APP會(huì)出現(xiàn)白屏秋泳。
優(yōu)化方案
解決方案一 修改啟動(dòng)Activity的主題
步驟一 styles.xml 添加Style
<style name="SplashTheme" parent="AppTheme">
<!-- 將splash圖片設(shè)置在這,這樣這張圖片取代白屏 -->
<item name="android:windowBackground">@drawable/bg_splash</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
步驟二 AndroidManifest.xml 添加啟動(dòng)頁主題
<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里做了很多耗時(shí)的初始化導(dǎo)致啟動(dòng)耗時(shí),那么我們可以試著優(yōu)化一下這里的初始化攒菠。介紹一樣?xùn)|西 :IntentService 迫皱。Service大家應(yīng)該會(huì)比較熟悉,那我簡(jiǎn)單的科普一下這個(gè)類。
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的子類要尔,根據(jù)需要處理異步請(qǐng)求(以intent表示)舍杜。客戶端通過調(diào)用startService(Intent) 發(fā)送請(qǐng)求赵辕,該Service根據(jù)需要啟動(dòng)既绩,使用工作線程處理依次每個(gè)Intent,并在停止工作時(shí)停止自身还惠。
這種“工作隊(duì)列處理器”模式通常用于從應(yīng)用程序的主線程中卸載任務(wù)饲握。 IntentService類的存在是為了簡(jiǎn)化這種模式。 要使用它蚕键,擴(kuò)展IntentService并實(shí)現(xiàn)onHandleIntent(Intent)救欧。 IntentService將收到Intents,啟動(dòng)一個(gè)工作線程锣光,并根據(jù)需要停止該服務(wù)笆怠。
所有請(qǐng)求都在單個(gè)工作線程處理 - 它們可能需要很長的時(shí)間(并且不會(huì)阻止應(yīng)用程序的主循環(huán)),但是一次只會(huì)處理一個(gè)請(qǐng)求誊爹。
IntentService與Service的區(qū)別
Android中的Service是用于后臺(tái)服務(wù)的蹬刷,當(dāng)應(yīng)用程序被掛到后臺(tái)的時(shí)候,問了保證應(yīng)用某些組件仍然可以工作而引入了Service這個(gè)概念频丘,那么這里面要強(qiáng)調(diào)的是Service不是獨(dú)立的進(jìn)程办成,也不是獨(dú)立的線程,它是依賴于應(yīng)用程序的主線程的搂漠,也就是說迂卢,在更多時(shí)候不建議在Service中編寫耗時(shí)的邏輯和操作,否則會(huì)引起ANR。
那么我們當(dāng)我們編寫的耗時(shí)邏輯而克,不得不被service來管理的時(shí)候靶壮,就需要引入IntentService,IntentService是繼承Service的拍摇,那么它包含了Service的全部特性亮钦,當(dāng)然也包含service的生命周期,那么與service不同的是充活,IntentService在執(zhí)行onCreate操作的時(shí)候,內(nèi)部開了一個(gè)線程蜡娶,去你執(zhí)行你的耗時(shí)操作混卵。
上面純粹幫你們百度了一波,其實(shí)我也不是很懂窖张,直接上代碼吧幕随。
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()))
{
//執(zhí)行百度地圖初始化
//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"/>
其實(shí)你可以理解開辟了另一個(gè)空間去執(zhí)行各種第三方啟動(dòng)的耗時(shí)操作∷藿樱看完本文的小伙伴,結(jié)合解決方案一和解決方案二,理論上能很大的解決APP啟動(dòng)白屏的問題了赘淮。