Giải quyết hiện tượng trắng/đen khi khởi động ứng dụng Android

Phân tích cơ chế khởi động lạnh

Quá trình khởi động trực quan được chia thành các giai đoạn sau:

  1. Hệ thống hiển thị nền cửa sổ mặc định (WindowBackground)
  2. Tạo tiến trình ứng dụng
  3. Khởi tạo Application
  4. Tạo và vẽ Activity đầu tiên
  5. Hiển thị nội dung cuối cùng

Hiện tượng trắng/đen xảy ra giữa giai đoạn 1 và 4 do khoảng trễ giữa nền mặc định và quá trình vẽ giao diện.

Nguyên nhân màu sắc khác biệt

Hiện tượng Thuộc tính chủ đề Ví dụ thực tế
Trắng android:windowBackground=@color/white Ứng dụng chủ đề sáng
Đen android:windowBackground=@color/black Ứng dụng chủ đề tối

Cơ chế quản lý cửa sổ

Dòng gọi tạo cửa sổ hệ thống:

WindowManagerGlobal.addView()
   ↓
ViewRootImpl.setView()
   ↓
WindowSession.addToDisplay() // Áp dụng nền cửa sổ
   ↓
Choreographer.doFrame() // Bắt đầu vẽ nội dung

Thời gian chênh lệch quan trọng: 200-500ms giữa khi thêm cửa sổ và hoàn thành khung đầu tiên.

Quy trình hệ thống chủ đề

Cấu hình styles.xml mẫu:

<style name="AppTheme" parent="Theme.Material.Light">
    <item name="android:windowBackground">@drawable/splash_bg</item>
    <item name="android:windowFullscreen">true</item>
</style>

Hệ thống chọn nền theo thứ tự:

  1. Chủ đề được chỉ định trong Activity
  2. Chủ đề được chỉ định trong Application
  3. Chủ đề mặc định của hệ thống

Phương pháp tối ưu hiện đại (Android 12+)

Sử dụng SplashScreen API

// 1. Định nghĩa chủ đề
<style name="SplashStyle" parent="Theme.SplashScreen">
    <item name="windowSplashScreenBackground">@color/splash_bg</item>
    <item name="windowSplashScreenAnimatedIcon">@drawable/app_logo</item>
</style>

// 2. Điều khiển trong Activity
class LaunchActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        splashScreen.setAnimationListener { splashView ->
            // Xử lý khi kết thúc
            splashView.remove()
        }
    }
}

Tối ưu hiệu năng

Đo lường thời gian khởi động

adb shell am start -W -n com.example/.LaunchActivity
# Giải thích kết quả:
ThisTime: Thời gian khởi động Activity cuối
TotalTime: Tổng thời gian khởi động
WaitTime: Thời gian hệ thống chờ AMS

Mục tiêu: TotalTime < 500ms để loại bỏ cảm nhận giật lag.

Chiến lược tối ưu

  • Tối ưu tải trước:
    System.loadLibrary("core_lib");
    <provider android:name="androidx.startup.InitializationProvider"
              android:authorities="com.example.initializer">
        <meta-data android:name="com.example.StartupTask"
                  android:value="androidx.startup"/>
    </provider>
  • Tối ưu vẽ:
    <ConstraintLayout tools:show="@layout/optimized_content">
        <include layout="@layout/simplified_first_screen"/>
    </ConstraintLayout>

Câu hỏi chuyên sâu

Câu hỏi: Tại sao SplashScreen API vượt trội hơn phương pháp truyền thống?
Trả lời: Ba ưu điểm chính:

  1. Chuẩn hóa hành vi trên các thiết bị
  2. Không ảnh hưởng hiệu năng (không thêm tầng vẽ)
  3. Quản lý động hiệu ứng vào/ra

Câu hỏi: Làm thế nào để tạo hiệu ứng splash theo thương hiệu?
Trả lời: Thực hiện theo từng lớp:

val splashManager = splashScreen
splashManager.setSplashScreenTheme(R.style.BrandAnimation)
if (Build.VERSION.SDK_INT >= 31) {
    splashManager.splashView.iconView.tintList = 
        ColorStateList.valueOf(getBrandColor())
}

Xu hướng công nghệ mới

  • Tải trước dự đoán (Android 13+):
    val predictor = context.getSystemService(AppPredictionService::class.java)
    predictor.registerPredictionUpdates(context, executor) { ... }
  • Phân loại khởi động:
    • Khởi động lạnh: Khởi tạo hoàn toàn
    • Khởi động ấm: Tái tạo Activity
    • Khởi động nóng: Phục hồi từ stack
  • Tối ưu bằng học máy:
    adb shell cmd package bg-dexopt-job com.example.app

Thẻ: SplashScreen API Android 12 WindowBackground App Startup ConstraintLayout

Đăng vào ngày 4 tháng 6 lúc 16:25