Android應用啓動白屏問題解決辦法
白屏問題是應用啓動過程中普遍存在的問題。
本文將介紹白屏問題的由來以及一種作者認爲是市場上比較普遍的解決辦法。
白屏問題的由來
我們已知當系統啓動並啓動App時需要消耗一定的時間,就算只有1s,也會讓用戶感覺有“延遲”現象。
我們在項目的MyApplication
中模擬一個1s的耗時
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
Thread.sleep(1000)
}
}
來看效果
這是Google設計者爲了讓用戶體會到點擊圖標後立馬就有響應,而讓App創建的過程中先展示一個空白窗口。
正是這個設計,我們在點擊App應用圖標之後,會看到一段時間的空白屏幕,這就是所謂的安卓應用啓動白屏。
總結就是:
谷歌設計App啓動的時候有一個預覽的界面,在應用完成啓動初始化之前都會顯示這個預覽界面,目的是爲了讓用戶點擊APP圖標的時候有一個瞬間響應的交互體驗。
而這個預覽界面是由我們app應用主題android:theme
中的android:windowBackground
屬性決定的,當我們不指定的時候android:windowBackground
的時候默認是一個近乎白色的顏色#fffafafa
。
來做一個代碼跟蹤
android:theme="@style/Theme.WhiteScreen"
查看應用主題---->
<style name="Theme.WhiteScreen" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
...
</style>
查看父主題---->
<style name="Theme.MaterialComponents.DayNight.DarkActionBar" parent="Theme.MaterialComponents.Light.DarkActionBar"/>
一直跟蹤到---->
<style name="Platform.AppCompat.Light" parent="android:Theme.Holo.Light">
...
<item name="android:windowBackground">@color/background_material_light</item>
</style>
---->
<color name="background_material_light">@color/material_grey_50</color>
---->
<color name="material_grey_50">#fffafafa</color>
我們看到android:windowBackground
屬性最終在Platform.AppCompat.Light
主題中指定,而background_material_light
對應的顏色正是#fffafafa
。
所以默認情況下,我們點擊應用圖標,在應用完成啓動初始化之前,看到的都是一個白色空白的屏幕。應用的啓動時間越長,這個白屏的顯示時間也就越長。
我們在MyApplication
中做一個耗時操作模擬應用啓動初始化
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
Thread.sleep(3000)
}
}
再來看效果,可以發現這時候白屏問題的解決就刻不容緩了。
解決方案
windowDisablePreview和windowIsTranslucent標籤
谷歌雖然在主題中有提供如windowDisablePreview
和windowIsTranslucent
等標籤,用來供用戶設置不顯示預覽窗口 或 者將預覽窗口設置爲透明 這樣兩種功能,從視覺上讓用戶無法看出黑白屏,但實際上這兩個標籤更像是爲了提供給開發者有這個選擇權利而提供的標籤,並不建議使用。
<!-- Base application theme. -->
<style name="Theme.WhiteScreen" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
...
<!--設置系統的取消預覽(空白窗口)爲true -->
<item name="android:windowDisablePreview">true</item>
<!--設置背景爲透明-->
<item name="android:windowIsTranslucent">true</item>
</style>
我們維持3s的延遲,然後將主題中的windowDisablePreview
或windowIsTranslucent
設置爲true後查看效果
我們看到點擊應用圖標後,App會卡頓在那裏,等待App啓動加載完成後再顯示第一個活動窗口。
這顯然是和Google官方的設計理念背道而馳的。
正確的解決方法一定是順着Google設計思想走,也就是讓用戶點擊應用圖標的時候有一個及時的響應交互。
改變android:windowBackground屬性,替換默認空白預覽頁面。
當我們替換android:windowBackground
屬性的值爲我們應用自定義的頁面。用戶點擊圖標在等待應用初始化加載的過程中,看到的不再是一個空白頁,而是一個與本應用相關的圖片,這樣就完美解決了應用創建過程中看到白屏的問題。其實這也正是市面上很普遍的解決方式。
在與Splash頁面做銜接的時候我們有兩種選擇
1、預覽頁與Splash頁面相同,Splash頁面顯示完成後直接跳到主頁面。
2、預覽頁與Splash頁面不同,先展示預覽頁,再展示Splash頁面,最後再跳到主頁面。
第一種,只要做到預覽頁和Splash頁面顯示效果完全相同,注意好適配即可,這裏就不做詳細描述了,感興趣的朋友可以直接下載Demo查看,我們直接來看效果。
Splash的標題欄也懶得去了,大家明白意思就行。
我們主要看一下比較常見的第二種選擇,因爲在實際的業務需求中,我們可能會在Splash頁面做一下頁面定製,如插播廣告等。這個時候就要求預覽頁與我們的閃屏頁不同,如何做呢,也很簡單。
1、自定義繼承自AppTheme的主題
<!-1:自定義主題-->
<style name="LauncherTheme" parent="Theme.WhiteScreen">
<item name="android:windowBackground">@drawable/layout_launcher</item>
</style>
2、將啓動Activity的theme設置爲自定義的主題
<activity
android:name=".SplashActivity"
android:theme="@style/LauncherTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
3、在啓動Activity的onCreate
方法中,在super.onCreate
和setContentView
方法之前調用setTheme
方法,將主題設置爲最初的AppTheme
class SplashActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// 注意這裏將主題設置迴應用的原有主題
setTheme(R.style.Theme_WhiteScreen)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
thread {
Thread.sleep(1000)
runOnUiThread(Runnable {startActivity(Intent(this, MainActivity::class.java))})
}
}
override fun onPause() {
super.onPause()
finish()
}
}
查看效果
這個效果圖在Spash頁會看到殘影,這是錄屏工具導致的,項目實際運行效果是看不到這個殘影的。
值得一提的是,最後這兩個效果,我們在MyApplication和SplashActivity中都是設置了延時的,現在你還能感覺到一絲絲的啓動白屏嗎?
文末有言
本篇文章的正文內容到這裏就結束了。要知道的是我們做的僅僅是從視覺方面消除了白屏問題,並沒有實際縮短應用的啓動時間,想做出一個優秀的App,啓動優化必須從有效縮短應用啓動時間入手。
我們可以點開淘寶App看一下,粗略估計啓動時間1s多。如果你覺得自己開發的應用沒有淘寶那麼複雜,啓動時間達到了3s甚至4s,那就是時候考慮真正地在啓動優化方面下點功夫了。
異步初始化,懶加載等都是我們值得借鑑和深入學習的技術。
文中Demo下載地址。