安卓項目實戰之啓動頁進入時(冷啓動)有短暫黑屏或白屏現象的終極解決方案

問題描述

在安卓項目開發中,我們在啓動app的時候,屏幕會出現一段時間的白屏或者黑屏,不同設備時間長短不同。很影響用戶體驗,所以我們很有必要對其進行優化。

黑白屏問題出現的原因

當我們啓動一個APP時,如果該app所屬的Application還沒有在後臺運行的話,系統會首先創建一個新的進程去運行這個APP,但進程的創建與初始化都是需要時間的,在這個動作完成之前,如果初始化的時間過長,屏幕上可能沒有任何動靜,用戶會以爲沒有點到APP而再次去點擊應用圖標,這極大的降低了用戶體驗,因此Android需要及時做出反饋去響應用戶的點擊啓動動作,這就有了StartingWindow(也稱之爲PreviewWindow的預覽窗口)的出現,這樣看起來就像App已經啓動起來了,只是數據內容還沒有初始化好。

StartingWindow一般出現在應用程序進程創建並初始化成功前,目的是告訴用戶,系統已經接受到操作,正在響應,在程序初始化完成後繪製好啓動頁UI,會同時移除這個窗口,所以他只是一個臨時的窗口。

一般情況下我們會對Application和Activity設置Theme,系統會根據設置的Theme初始化StartingWindow。Window佈局的頂層是DecorView,StartingWindow顯示一個空DecorView,但是會給這個DecorView應用這個Activity指定的Theme中設置的背景色,如果這個Activity沒有指定Theme就用Application的Theme(Application系統要求必須設置Theme),我們在Style中的設置就決定了顯示的是白屏還是黑屏,如下:

<application
        // ....
        android:theme="@style/AppTheme">

如果我們的AppTheme像如下定義的一樣使用了Light主題,那麼顯示就是白屏,反之如果使用Black主題,那麼顯示就是黑屏:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

解決方案

1、首先在res/drawable下新建一個layer-list,名字隨便取,比如splash.xml:
layer-list的編寫參考:https://www.jb51.net/article/130850.htm

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 背景顏色 -->
    <item android:drawable="@color/white" />

    <item>
        <!-- 圖片 -->
        <bitmap
            android:gravity="center"
            android:src="@drawable/wel_page" />
    </item>
</layer-list>

layer-list大家都會寫吧,上面是背景顏色,下面是一張圖,這張圖可以是全屏的圖,可以是一張小圖。如果是全屏的圖,那上面的顏色也可以不用設置,如果是小圖,就要指定下顏色了,並且可以指定圖片所在位置。

如果想讓圖片填充整個空間:設置gravity如下:

android:gravity="fill_horizontal|fill_vertical"

2、給主題設置Window背景:可以用我們上面的layer-list作爲背景,當然也可以設置個全屏的圖片。

<style name="SplashTheme" parent="AppBaseTheme">
    <!-- 歡迎頁背景引用剛纔寫好的 -->
    <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:這裏注意application使用的theme是AppTheme,而SplashActivity使用的主題是SplashTheme。這樣做的效果是隻要SplashActivity使用StartAppTheme主題,其他Activity都是用AppTheme主題哦。

<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的實現,在onCreate()中直接啓動你的MainActivity即可,沒有setContentView():

public class SplashActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // setContentView(R.layout.activity_splash);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Intent intent = new Intent(SplashActivity.this,MainActivity.class);
                startActivity(intent);
                finish();
            }
        }, 3000);
    }
}

擴展

在上面第二步中提到可以不使用layer-list,直接設置背景爲圖片,但是不推薦使用直接使用.png圖片作爲背景的方式,因爲屏幕尺寸太多,圖片顯示會變形,如果可以我們也可以使用.9.png的背景圖來實現,但是使用圖片的方式存在一個缺陷就是splash圖片是寫在theme中的,圖片的內存釋放不掉,而使用layer-list比較節省內存。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章