解決Splash白屏黑屏問(wèn)題

當(dāng)系統(tǒng)啟動(dòng)一個(gè)App時(shí)柄冲,zygote進(jìn)程會(huì)首先創(chuàng)建一個(gè)新的進(jìn)程去運(yùn)行這個(gè)App放典,但是進(jìn)程的創(chuàng)建是需要時(shí)間的,在創(chuàng)建完成之前巡社,界面是呈現(xiàn)假死狀態(tài)的膛堤,這極大地降低了用戶體驗(yàn),Android需要及時(shí)做出反饋去避免這段迷之尷尬晌该。于是系統(tǒng)根據(jù)你的Manifest文件設(shè)置的主題顏色的不同來(lái)展示一個(gè)白屏(黑屏)肥荔。而這個(gè)白屏(黑屏)正式的稱呼就是Preview Window,即預(yù)覽窗口朝群。這篇文章主要剖析App冷啟動(dòng)時(shí)的兩個(gè)問(wèn)題:

  • App啟動(dòng)時(shí)白屏(黑屏)
  • App啟動(dòng)速度慢燕耿,如何點(diǎn)擊秒開


    啟動(dòng)黑屏白屏

APP啟動(dòng)時(shí)白屏(黑屏)

Activity如何繪制

首先要說(shuō)明的是無(wú)論App啟動(dòng),還是startActivity都是Activity的啟動(dòng)姜胖,所以這歸根結(jié)底是一個(gè)問(wèn)題誉帅,究其原因是對(duì)Activity的啟動(dòng)機(jī)制不太了解。Activity啟動(dòng)時(shí)繪制整個(gè)窗口需要按順序執(zhí)行以下幾個(gè)步驟:

  1. 繪制背景
  2. 繪制View本身的內(nèi)容
  3. 繪制子View
  4. 繪制修飾內(nèi)容(例如滾動(dòng)條)

閃屏原因剖析Preview Window

我們正常開發(fā)中會(huì)在Activity的onCreate()方法中調(diào)用setContentView(View)設(shè)置該Activity的顯示布局右莱,那么問(wèn)題就來(lái)了蚜锨,既然我們?cè)O(shè)置了布局,為什么啟動(dòng)的時(shí)候還會(huì)白屏或者黑屏而不是顯示我set的布局呢慢蜓?下面就帶領(lǐng)大家一起來(lái)剖析一下原因亚再。

當(dāng)打開一個(gè)Activity時(shí),如果這個(gè)Activity所屬Application還沒(méi)有在運(yùn)行晨抡,系統(tǒng)會(huì)為這個(gè)Activity的創(chuàng)建一個(gè)進(jìn)程针余,但進(jìn)程的創(chuàng)建與初始化都需要時(shí)間饲鄙,在這個(gè)動(dòng)作完成之前,如果初始化的時(shí)間過(guò)長(zhǎng)圆雁,屏幕上可能沒(méi)有任何動(dòng)靜忍级,用戶會(huì)以為沒(méi)有點(diǎn)到按鈕。所以既不能停在原來(lái)的地方又沒(méi)到顯示新的界面伪朽,怎么辦呢轴咱?這就有了StartingWindow(也稱之為Preview Window)的出現(xiàn),這樣看起來(lái)就像Activity已經(jīng)啟動(dòng)起來(lái)了烈涮,只是數(shù)據(jù)內(nèi)容還沒(méi)有初始化好朴肺。

StartingWindow一般出現(xiàn)在應(yīng)用程序進(jìn)程創(chuàng)建并初始化成功前,所以它是個(gè)臨時(shí)窗口坚洽,對(duì)應(yīng)的WindowType是TYPE_APPLICATION_STARTING戈稿。目的是告訴用戶,系統(tǒng)已經(jīng)接受到操作讶舰,正在響應(yīng)鞍盗,在程序初始化完成后實(shí)現(xiàn)目標(biāo)UI,同時(shí)移除這個(gè)窗口跳昼。

這個(gè)StartingWindow就是我們要討論的白屏(黑屏)的\color{red}{元兇}般甲,一般情況下我們會(huì)對(duì)Application和Activity設(shè)置theme,系統(tǒng)會(huì)根據(jù)設(shè)置的theme初始化StartingWindow鹅颊。Window布局的頂層是DecorView敷存,StartingWindow顯示一個(gè)空DecorView,但是會(huì)給這個(gè)DecorView應(yīng)用這個(gè)Activity指定的theme堪伍,如果這個(gè)Activity沒(méi)有指定theme就用Application的锚烦。

在theme中可以指定窗口的背景、Activity的Icon帝雇、App整體文字顏色等涮俄,如果說(shuō)沒(méi)有指定任何屬性,就會(huì)用默認(rèn)的屬性摊求,也就是上文中提到的空DecorView,所以我們的白屏(黑屏)和空DecorView息息相關(guān)刘离,我們給Application設(shè)置的Style就決定了是白屏還是黑屏室叉。

1、如果選擇了Black系列的主題那么Activity跳轉(zhuǎn)的時(shí)候就是黑屏:

@android:style/Theme.Black

2硫惕、如果選擇了Light系列的主題那么Activity跳轉(zhuǎn)的時(shí)候就是白屏:

@android:style/Theme.Light

3茧痕、常見(jiàn)Theme主題

android:theme="@android:style/Theme.Dialog"                // Activity顯示為對(duì)話框模式
android:theme="@android:style/Theme.NoTitleBar"            // 不顯示應(yīng)用程序標(biāo)題欄=
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" // 不顯示應(yīng)用程序標(biāo)題欄,并全屏
android:theme="Theme.Light "                               // 背景為白色
android:theme="Theme.Light.NoTitleBar"                     // 白色背景并無(wú)標(biāo)題欄
android:theme="Theme.Light.NoTitleBar.Fullscreen"          // 白色背景恼除,無(wú)標(biāo)題欄踪旷,全屏
android:theme="Theme.Black"                                // 背景黑色
android:theme="Theme.Black.NoTitleBar"                     // 黑色背景并無(wú)標(biāo)題欄
android:theme="Theme.Black.NoTitleBar.Fullscreen"          // 黑色背景曼氛,無(wú)標(biāo)題欄,全屏
android:theme="Theme.Wallpaper"                            // 用系統(tǒng)桌面為應(yīng)用程序背景
android:theme="Theme.Wallpaper.NoTitleBar"                 // 用系統(tǒng)桌面為應(yīng)用程序背景令野,且無(wú)標(biāo)題欄
android:theme="Theme.Wallpaper.NoTitleBar.Fullscreen"      // 用系統(tǒng)桌面為應(yīng)用程序背景舀患,無(wú)標(biāo)題欄,全屏
android:theme="Theme.Translucent"                          // 透明背景
android:theme="Theme.Translucent.NoTitleBar"               // 透明背景并無(wú)標(biāo)題
android:theme="Theme.Translucent.NoTitleBar.Fullscreen"    // 透明背景并無(wú)標(biāo)題气破,全屏
android:theme="Theme.Panel "                               // 面板風(fēng)格顯示
android:theme="Theme.Light.Panel"                          // 平板風(fēng)格顯示

解決辦法

\color{red}{通常的解決辦法都是給Activity設(shè)置一個(gè)透明背景的主題:}

<style name="SplashTheme" parent="AppTheme">
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowIsTranslucent">true</item>
</style>

如上設(shè)置后App和Activity啟動(dòng)時(shí)聊浅,我們的StartingWindow會(huì)應(yīng)用我們這個(gè)透明背景的主題,跳轉(zhuǎn)時(shí)確實(shí)沒(méi)有白屏和黑屏了现使,但是這樣設(shè)置會(huì)產(chǎn)生如下后果:

  • 給SplashActivity設(shè)置透明Theme后低匙,用戶點(diǎn)擊我們App圖標(biāo)后,需要等待2秒左右的時(shí)候才會(huì)顯示contentView碳锈。造成了App啟動(dòng)速度慢的假象顽冶,其實(shí)Activity已經(jīng)啟動(dòng)了,只是background是透明的售碳,這時(shí)候你點(diǎn)擊桌面的其他地方是無(wú)效的强重。
  • 給其他Activity設(shè)置后,會(huì)導(dǎo)致通過(guò)overridePendingTransition設(shè)置的啟動(dòng)關(guān)閉Activity的動(dòng)畫無(wú)效团滥。需要在style中重新寫如下幾個(gè)動(dòng)畫:
<style name="AppTheme" parent="AppBaseTheme">
    <item name="android:windowAnimationStyle">@style/Animation.Activity.Translucent.Style</item>
    <item name="android:windowFullscreen">true...
    <item name="android:windowIsTranslucent">true...
</style>
 
<style name="Animation.Activity.Style" parent="@android:style/Animation.Activity">
    <item name="android:activityOpenEnterAnimation">...
    <item name="android:activityOpenExitAnimation">...
    <item name="android:activityCloseEnterAnimation">...
    <item name="android:activityCloseExitAnimation">...
</style>
 
<style name="Animation.Activity.Translucent.Style" parent="@android:style/Animation.Translucent"> 
    <item name="android:windowEnterAnimation">...
    <item name="android:windowExitAnimation">...
</style>
  • Activity之間的跳轉(zhuǎn)可能偶爾會(huì)看到桌面一閃而過(guò)(如果SplashActivity和其他Activity都設(shè)置了透明)竿屹。

小結(jié):一般情況下是只會(huì)給SplashActivity設(shè)置一個(gè)透明背景的主題,其他Activity不會(huì)設(shè)置灸姊,經(jīng)過(guò)實(shí)踐拱燃,這種體驗(yàn)是最好的。但是如果要做到App秒開還是不行的力惯,和我們的文章開頭所分析的原理相斥了碗誉。

秒開方案

還是要從 ActivityTheme 下手,既然可以讓 Window 白屏(黑屏)或者透明父晶,那么是不是可以設(shè)置其它顏色或者圖片來(lái)實(shí)現(xiàn)App的秒開呢哮缺?答案是肯定的。

實(shí)現(xiàn)原理

我們之前設(shè)置了Window透明甲喝,實(shí)現(xiàn)了去掉白屏和黑屏尝苇,現(xiàn)在要弄一個(gè)顏色或者圖片來(lái)代替白屏和黑屏,所以首先要把原來(lái)style中的透明屬性去掉埠胖。然后給Window設(shè)置一個(gè)背景顏色或者圖片糠溜。

實(shí)現(xiàn)步驟

1、首先在res/drawable下新建一個(gè)layer-list直撤,名字隨意非竿,比如splash.xml:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 背景顏色 -->
    <item android:drawable="@color/white" />
 
    <item>
        <!-- 如果是全屏圖時(shí)上面顏色可以不設(shè)置;如果是小圖就必須設(shè)置下顏色 -->
        <bitmap
            android:gravity="center"
            android:src="@drawable/splash_logo_page" />
    </item>
</layer-list>

2谋竖、給主題設(shè)置Window背景:

<style name="SplashTheme" parent="AppBaseTheme">
    <!-- Splash頁(yè)設(shè)置背景红柱,當(dāng)然頁(yè)可以直接用全屏圖片 -->
    <item name="android:windowBackground">@drawable/splash</item>
    <item name="android:windowFullscreen">true</item>
    <!-- <item name="android:windowIsTranslucent">true</item> --> <!-- 透明背景不要了 -->
</style>

3承匣、在AndroidManifest.xml中定義SplashActivity的theme為SplashTheme:

<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>

4、SplashActivity的實(shí)現(xiàn)锤悄,在onCreate()啟動(dòng)你的MainActivity即可韧骗,其他什么都別干:

public class SplashActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        startActivity(new Intent(this, MainActivity.class));
        finish();
    }
}

特別注意:

  • 為保證啟動(dòng)速度,SplashActivity不要調(diào)用setContentView()方法铁蹈。因?yàn)?code>Activity設(shè)置了layout宽闲,它在App完全初始化完成后才會(huì)顯示,也會(huì)耗時(shí)握牧。使用該啟動(dòng)畫面實(shí)現(xiàn)也能兼容到上面說(shuō)的白屏和黑屏的問(wèn)題容诬。跟上面的小結(jié)一樣,其他Activity不要設(shè)置
  • 如果Splash有閃屏或者廣告投放之類的業(yè)務(wù)沿腰,可以setContentView()并做相關(guān)邏輯览徒,切忌耗時(shí)操作
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市颂龙,隨后出現(xiàn)的幾起案子习蓬,更是在濱河造成了極大的恐慌,老刑警劉巖措嵌,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件躲叼,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡企巢,警方通過(guò)查閱死者的電腦和手機(jī)枫慷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)浪规,“玉大人或听,你說(shuō)我怎么就攤上這事∷裥觯” “怎么了誉裆?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)缸濒。 經(jīng)常有香客問(wèn)我足丢,道長(zhǎng),這世上最難降的妖魔是什么庇配? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任斩跌,我火速辦了婚禮,結(jié)果婚禮上讨永,老公的妹妹穿的比我還像新娘滔驶。我一直安慰自己遇革,他們只是感情好卿闹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布揭糕。 她就那樣靜靜地躺著,像睡著了一般锻霎。 火紅的嫁衣襯著肌膚如雪著角。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天旋恼,我揣著相機(jī)與錄音吏口,去河邊找鬼。 笑死冰更,一個(gè)胖子當(dāng)著我的面吹牛产徊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蜀细,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼舟铜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了奠衔?” 一聲冷哼從身側(cè)響起谆刨,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎归斤,沒(méi)想到半個(gè)月后痊夭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡脏里,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年她我,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膝宁。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鸦难,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出员淫,到底是詐尸還是另有隱情合蔽,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布介返,位于F島的核電站拴事,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏圣蝎。R本人自食惡果不足惜刃宵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望徘公。 院中可真熱鬧牲证,春花似錦、人聲如沸关面。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至捂齐,卻和暖如春蛮放,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背奠宜。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工包颁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人压真。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓娩嚼,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親滴肿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子待锈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355