Android Splash界面解決白屏、黑屏等問題

前言

我相信很多Android開發同學都遇到過這樣的需求:

  1. 實現一個Splash界面,界面上有應用相關的背景圖片和一個開始按鈕.
  2. 點擊按鈕之後進入主頁,以後用戶再打開應用就不顯示這個Splash界面了.

也相信很多同學都遇到了這樣的困惑:

  • 第二次進入應用,儘管你在Splash界面已經直接跳轉到首頁了,但是還是有個白屏或者黑屏或者帶ActionBar的白屏閃現一下.

如果你也遇到這個問題,那就繼續閱讀這篇文章,我帶大家去分析和解決這個問題.


解決方案

這裏我們先給出解決方案,然後再具體分析產生原因哈.避免分析的大段文字阻礙了同學學習的熱情.

解決方案非常簡單,一句話概括是:給Splash Activity設置一個主題,主題內容是:全屏+透明.

style.xml增加SplashTheme主題:

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

AndroidManifest.xml中爲SplashActivity配置主題:

<activity android:name=".activity.SplashActivity"
    android:theme="@style/SplashTheme">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

經過如上配置,困擾你的白屏、黑屏、ActionBar屏應該都已經煙消雲散了.爲了知其然,並知其所以然,希望同學能繼續跟我一起分析一下這些白屏產生的原因.


Activity組件的窗口啓動過程

首先聲明,本段內容大量參考了羅昇陽老師的博客。爲了方便理解,對其內容進行了壓縮。如果侵權,我立刻刪掉這段分析哈。

想要了解白屏產生的根源,就不得不去跟蹤Activity組件的窗口啓動過程。Activity組件在啓動的過程中,會調用ActivityStack類的成語函數startActivityLocked方法。注意,在調用ActivityStack類的成語函數startActivityLocked方法的時候,Activity組件還處於啓動過程中,即它的窗口尚未顯示出來,不過這時候ActivityManagerService服務會檢查是否需要爲正在啓動的Activity組件顯示一個啓動窗口。如果需要的話,那麼ActivityManagerService服務就會請求WindowManagerService服務爲正在啓動的Activity組件設置一個啓動窗口(ps:而這個啓動窗口就是白屏的由來)。


1. ActivityStack.startActivityLocked

public class ActivityStack {
    // set to false to disable the preview that is shown while a new activity
    // is being started.
    static final boolean SHOW_APP_STARTING_PREVIEW = true;

    private final void startActivityLocked(ActivityRecord r, boolean newTask, boolean doResume) {
        final int NH = mHistory.size();

        int addPos = -1;

        // Place to new activity at top of stack, so it is next to interact
        // with the user.
        if (addPos < 0) {
            addPos = NH;
        }

        // Slot the activity into the history stack and proceed
        mHistory.add(addPos, r);

        if (NH > 0) {
            // We want to show the starting preview window if we are
            // switching to a new task, or the next activity's process is
            // not currently running.
            boolean showStartingIcon = newTasks;
            ProcessRecord proc = r.app;
            if (proc == null) {
                proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
            }
            if (proc == null || proc.thread == null) {
                showStartingIcon = true;
            }


        }
    }
}

未完待續…

發佈了542 篇原創文章 · 獲贊 1072 · 訪問量 286萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章