天天看點

android 程式白屏,Android冷啟動白屏問題

1. 冷啟動與熱啟動

通常我們在使用某個應用程式時,都是點選桌面應用圖示來啟動該程式。你肯定或多或少的碰到過這種情況:應用啟動的一刹那,手機會先白屏或者黑屏一段時間,然後再進入應用程式的首頁,但是你退出應用後再次打開APP,确又發現白屏時間極短或者壓根感覺不出來。

上面這種現象,涉及到2個概念:冷啟動與熱啟動,我們先來了解下這2個術語是什麼意思。

冷啟動:當啟動某個應用程式時,如果Android手機系統發現背景沒有該應用程式的程序,則會先建立一個該應用程式程序,這種方式叫冷啟動。

熱啟動:當啟動某個應用程式時,系統背景已經有一個該應用程式的程序了,則不會再建立一個新的程序,這種方式叫熱啟動。通常,我們按傳回鍵退出應用,按home鍵回到桌面,該應用程序還一直存活,再次啟動應用都叫熱啟動。

需要注意的是,現在很多手機都有一鍵清理記憶體的功能,例如小米、華為等手機,還有類似騰訊手機管家之類的軟體,也可實作類似功能。采用這些方式清理記憶體後,應用程序被殺掉了,再次啟動應用,都屬于冷啟動了。

2. 白屏原因

通常情況下,白屏現象都是在冷啟動情況下出現的,如果白屏時間過長,就會給人一種APP很卡頓的感覺。

應用程式啟動時,系統會從zygote程序fork一個新的程序給程式使用,接着會建立和初始化Application類,再接着就是建立和初始化啟動頁Activity類了,隻有啟動頁Activity能夠在視窗顯示出來之後,我們才能在裝置上看到應用的程式的第一幀了。其大概流程可總結為:

從zygote程序fork出新程序 --> 建立Application類 --> Application.attachBaseContext() --> Application.onCreate() --> 建立入口Activity類 -> Activity.onCreate() --> Activity.onStart() --> Activity.onResume()

由此可見,冷啟動可簡單總結為3個步驟:

1.從zygote程序fork出一個新程序,這個步驟所需時間可忽略,因為我們無法控制;

2.建立Application類并初始化,主要是執行Application.onCreate()方法;

3.建立并初始化入口Activity類,并在視窗上繪制UI;

熱啟動時,相比冷啟動少了1、2這2個步驟,步驟1我們不考慮,是以我們可初步判定Application.onCreate()執行比較耗時,才出現了白屏現象。可以自己寫個demo驗證,在Application.onCreate()方法裡使線程停頓幾秒鐘,冷啟動打開應用時就會發現白屏時間延長了幾秒鐘。

我們現在開發Android應用程式時,通常都會內建很多第三方SDK,這些SDK大多都需要在Application.onCreate()裡進行初始化,同時我們自己的應用也有很多需要在這裡進行初始化,這樣導緻了Application.onCreate()方法執行時間會很長。

但是Application.onCreate()執行時間過長跟應用啟動白屏有什麼關系呢?我們看到的界面,其實都是在手機window上繪制出來的,我們開發時的Activity并不是一個能看到的界面,它最終能顯示出來,都需要通過measure、layout等過程之後,在window上繪制,我們才能看到界面。在應用啟動之後,window就已經存在了,Application初始化時,會從配置的Theme裡,讀取一個名為“android:windowBackground”的屬性,顧名思義就是視窗背景,該背景就會在window上繪制出來,同樣我們也能看到了。如果我們采用的Theme裡,沒有覆寫該屬性值,則會采用該Theme的預設值,大部分系統提供的Theme裡,windowBackground都是白色,是以我們會看到白屏了。如果windowBackground屬性值是黑色,我們就會看到黑屏了,如果是透明色,我們會發現應用卡頓之後才能看到程式界面。

3. 消除啟動時的白屏/黑屏

3.1 優化Application.onCreate()方法

這裡給出幾點建議:

盡量不要在Application裡做耗時的操作,例如讀寫檔案、資料庫等;

各種第三方SDK,看能否在需要使用的時候進行初始化;

某些耗時的初始化方法能否放到線程裡異步執行;

建議歸建議,但實際開發時會發現很難,好多操作都非得放在Application裡執行,移出去很困難,特别是很多老工程,你都不能預料到會出現什麼幺蛾子。

3.2 設定android:windowBackground屬性

在styles.xml裡定義一個style,設定windowBackground屬性:

@drawable/launch_bg

true

配置入口Activity的theme屬性為上面定義的style:

android:name=".LaunchActivity"

android:configChanges="orientation|screenSize|keyboardHidden"

android:screenOrientation="portrait"

android:theme="@style/LaunchTheme">

windowBackground屬性可以配置任意drawable,比方說與你啟動頁一樣的圖檔,這樣在冷啟動時就能立馬看到這張圖檔展示出來,然後跳轉到啟動頁時,能做到視覺上的無縫過渡,這樣就能讓應用程式看起來是秒啟動。

需要注意的是,這裡的style我們繼承自@android:style/Theme.Light.NoTitleBar.Fullscreen,如果你的LaunchActivity繼承自AppCompatActivity,那麼啟動該Activity時會直接報錯,因為AppCompatActivity必須采用繼承自Theme.AppCompat的主題。

那有人說了,如果是這樣,那我們就采用Theme.AppCompat.Light.NoActionBar好了,一般情況下這樣也沒問題。但是當你在某些有虛拟按鍵的手機上,會發現冷啟動時你配置的圖檔占據了整個螢幕(底部虛拟按鍵的地方會擋住你的圖檔),然後進入啟動頁時,圖檔顯示的區域又不包含底部虛拟按鍵的地方了,這樣過渡就不平滑,使用者體驗不佳。但是采用我們之前定義的那個style,就不會出現這個問題了。這個問題困擾了我好久,後來才發現采用Theme.Light.NoTitleBar.Fullscreen才能解決這種相容性問題,希望對大家有所幫助。