iT邦幫忙

2025 iThome 鐵人賽

DAY 13
0
Mobile Development

Android 性能戰爭:從 Profiler 開始的 30 天優化實錄系列 第 13

# Day 13:【啟動戰役】閃屏頁 (Splash Screen) 的最佳實踐

  • 分享至 

  • xImage
  •  

各位戰士,歡迎來到第十三天的戰場。至今,我們所有的努力都集中在「縮短」冷啟動的時間上。但無論我們優化得多好,從使用者點擊圖示到 App 完全可互動,總會有一個短暫的等待期。

這段時間,使用者看到的是什麼?是短暫的白畫面?還是設計粗糙的啟動圖?這第一印象至關重要。一個糟糕的閃屏頁不僅會讓前面的速度優化成果大打折扣,甚至可能給使用者帶來「這個 App 很慢」的錯覺。

今天,我們的任務就是將這段等待時間,從一段惱人的延遲,轉變為一次優雅、無縫的品牌展示


錯誤的戰術:postDelayed 的延遲閃屏

在古老的戰場上,許多開發者會用一種錯誤的方式來實作閃屏頁:

  1. 建立一個 SplashActivity,其佈局只有一個 Logo。
  2. onCreate 中使用 Handler.postDelayed() 或類似的計時器。
  3. 等待 2-3 秒後,啟動 MainActivity 並關閉自己。

這是一個災難性的戰術!

它不僅沒有解決冷啟動時的白畫面問題,反而人為地增加了不必要的等待時間。使用者被迫看完一個固定的動畫,即便 App 本身已經準備好了。這種做法違背了我們性能優化的初衷。在我們的戰爭中,這是必須被拋棄的戰術。


正確的戰術(傳統版):windowBackground

在 Android 12 出現之前,業界的最佳實踐是利用 windowBackground 屬性來消除冷啟動的白畫面。原理是:在系統為 App 建立主視窗時,立刻為這個視窗設定一個帶有 Logo 的背景,而不是等 ActivitysetContentView() 執行完畢才顯示內容。

雖然這個方法依然有效,但現在我們有了更現代化、功能更強大的官方武器。


現代化的終極武器:Android 12+ 的 SplashScreen API

Google 在 Android 12 中推出了一套全新的 SplashScreen API,並透過 androidx.core:core-splashscreen 函式庫將其向後相容至所有 API Level。這是當前實作閃屏頁的唯一推薦方式

它的優勢:

  • 統一體驗:在 Android 12+ 裝置上,所有 App 的啟動動畫(圖示放大)行為都將保持一致。
  • 無縫過渡:提供流暢的「退出動畫」,讓閃屏頁平滑地過渡到你的 App 主畫面。
  • 數據預載:允許你在閃屏頁顯示的同時,在背景載入必要的初始數據,載入完成後再優雅地關閉閃屏頁。
  • 向後相容:在舊版 Android 上,它會自動降級,提供類似 windowBackground 的靜態閃屏頁體驗。

實作步驟

第一步:加入依賴

在你的 :app 模組的 build.gradle.kts 中,加入 SplashScreen 函式庫:

// In app/build.gradle.kts
dependencies {
    // ... other dependencies
    implementation("androidx.core:core-splashscreen:1.0.1") // 建議使用最新版本
}

第二步:建立閃屏頁主題

res/values/themes.xml 中,建立一個專門用於閃屏頁的主題。它的 parent 必須是 Theme.SplashScreen 或其子類。

<style name="Theme.App.Starting" parent="Theme.SplashScreen">
    <item name="windowSplashScreenBackground">@color/white</item>
    
    <item name="windowSplashScreenAnimatedIcon">@drawable/ic_splash_logo</item>
    
    <item name="postSplashScreenTheme">@style/Theme.MyApp</item>
</style>

第三步:在 Manifest 中應用主題

打開 AndroidManifest.xml,將你的啟動 Activity (通常是 MainActivity) 的 android:theme 屬性指向我們剛剛建立的 Theme.App.Starting

<activity
    android:name=".MainActivity"
    android:exported="true"
    android:theme="@style/Theme.App.Starting">  <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

第四步:在 Activity 中安裝閃屏頁

最後,在你的啟動 ActivityonCreate 方法中,呼叫 installSplashScreen()

⚠️ 重要: 這個呼叫必須在 super.onCreate()setContentView() 之前。

// In MainActivity.kt

import android.os.Bundle
import androidx.activity.ComponentActivity // or androidx.appcompat.app.AppCompatActivity
import androidx.activity.viewModels
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen

class MainActivity : ComponentActivity() {

    private val viewModel: MainViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        // Handle the splash screen transition.
        val splashScreen = installSplashScreen() // ‼️ 必須在 super.onCreate() 之前

        super.onCreate(savedInstanceState)
        
        // [進階用法] 讓閃屏頁持續顯示,直到初始數據載入完畢
        // 我們告訴閃屏頁:請保持顯示,直到 viewModel.isReady 的狀態變為 true
        splashScreen.setKeepOnScreenCondition { !viewModel.isReady.value }

        setContentView(R.layout.activity_main)
    }
}

在上面的進階用法中,我們使用了 setKeepOnScreenCondition。這是一個極其強大的功能,它允許 App 在 ViewModel 或其他地方非同步載入數據(例如從網路或資料庫讀取初始設定),同時保持閃屏頁的顯示。一旦數據準備就緒 (viewModel.isReady.value 變為 true),條件不再滿足,閃屏頁就會播放退出動畫並自動消失。

今日總結

今天,我們為啟動戰役畫上了完美的句點。我們學會了:

  • 拋棄了 postDelayed 這種過時且有害的閃屏頁實作方式。

  • 掌握了 SplashScreen 這個現代化、官方推薦的終極武器。

  • 學會了 如何設定閃屏頁的主題,並在 Activity 中安裝它。

  • 了解了 如何使用 setKeepOnScreenCondition 來優雅地處理數據預載,實現真正的無縫體驗。

速度與體驗,兩者兼得。至此,我們應用程式的「門面」已經煥然一新。使用者將在一次極速且流暢的啟動中,開啟我們的應用。

第一場大型戰役——應用啟動速度優化戰役——至此大獲全勝。明天,我們將對過去一週的戰果進行全面的數據檢視與總結,為下一場戰爭做好準備!

我們明天見!


上一篇
# Day 12:【啟動戰役】實作 Baseline Profiles
下一篇
# Day 14:【啟動戰役】戰果驗收:數據對比與總結
系列文
Android 性能戰爭:從 Profiler 開始的 30 天優化實錄15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言