スプラッシュスクリーンのステップを調整し、スタック(白い画面)ピットを開始します

Android 12 のスプラッシュ画面

Android 12 以降、すべてのアプリのコールド スタートおよびウォーム スタート中に、システムは常に Android システムのデフォルトのスプラッシュ画面を適用します。デフォルトでは、このシステムのデフォルトのスプラッシュ画面は、アプリのランチャー アイコン要素とテーマの windowBackground (モノクロの場合) で構成されます。

つまり、アプリケーションが Android 12 システムで実行されている限り、影響を受けます。Alipay を例に挙げます。2023 年 1 月 24 日現在、Android 13 システムでコールド スタートすると、明らかに A が表示されます。スプラッシュ ページが表示され、ページの中央に起動アイコンが表示されます。これはシステムの影響を受けており、適応されていません。

画像の説明を追加してください

GoogleはAndroidの起動スタイルを統一したいはずだが、それはちょっと遅すぎる、国内のアプリ起動ページは単純な表示だけでなく広告も表示され、スタイルも異なる. 独自の起動UIを持っているため、国産アプリにとってこのスプラッシュスクリーンの起動は負担となります。
ただし、適切でないと起動時に見た目がおかしくなったり、スプラッシュ画面が 2 ページ表示されたりするため、やはり勇気を持って調整する必要があります。

スプラッシュスクリーンの適応

適応方法も非常に簡単で、公式ドキュメントの手順に従うだけです。
公式の提案では、AndroidX では SplashScreen API を使用し、下位互換性のある SplashScreen ライブラリを使用することが提案されており、すべての Android バージョンで同じ外観とスタイルのスプラッシュ スクリーンを表示できると公式は主張しています。

しかし、これは実際の使用には当てはまりません。たとえば、アニメーションは Android 12 より前のシステムでは有効になりません。アニメーションが必要な場合は、他の方法を使用して自分で実現できます。ただ画像を表示するだけでは、アニメーションは機能しません。影響を受ける。

適応手順は次のとおりです

compileSdkVersion を 31 以降に変更します

compileSdkVersion 31

依存関係を追加する

implementation 'androidx.core:core-splashscreen:1.0.0'

起動ページに表示する画像やアニメーションを用意する

ここに画像の説明を挿入

トピックを追加

    <style name="Theme.App.SplashScreen" parent="Theme.SplashScreen">
        <!--背景颜色-->
        <item name="windowSplashScreenBackground">@color/white</item>
        <!--设置动画或图片,注意动画在Android12 以下不生效 很难受...-->
        <item name="windowSplashScreenAnimatedIcon">
            @drawable/ic_splash
        </item>
        <!--动画执行时间-->
        <!--        <item name="windowSplashScreenAnimationDuration">1000</item>-->
        
        <!--设置闪屏也后启动页面的主题 说白了 就是app本来的主题-->
        <item name="postSplashScreenTheme">@style/Theme.XeonYuTheme</item>

    </style>

スプラッシュ ページを作成する SplashActivity
最初にページのテーマを指定します
ここに画像の説明を挿入

次にコードがあります。コードは非常に単純です。他に要件がない場合は、 oncCreate で呼び出してinstallSplashScreen()、通常どおりページにジャンプします。

class SplashActivity : AppCompatActivity() {
    
    
    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        /*setContentView 可不写*/
//        setContentView(R.layout.activity_splash)
        /*创建与页面关联的SplashScreen实例*/
        installSplashScreen()
        /*跳转页面*/
        val intent = Intent(this, MainActivity::class.java)
        startActivity(intent)
    }
}

それからそれを実行して見て
画像の説明を追加してください
ください。非常に単純なスタート画面ページが正常に表示されていることがわかります。

スプラッシュ画面にポップアップを表示する

通常の状況では、ユーザーが初めてアプリを開いたときにプライバシー規約に同意するためのウィンドウをポップアップ表示し、初期化操作などを行う必要があります。この場合、ユーザーはジャンプする前に [同意する] をクリックする必要があります。

setKeepOnScreenConditionこの時点で、コーディネートを使用できますsetOnExitAnimationListener。サンプルコードは次のとおりです。


class SplashActivity : AppCompatActivity() {
    
    

    /**
     * 控制是否保持启动页面的变量,值为false时继续往下走
     */
    private val keepOnScreenCondition = AtomicBoolean(true)

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        /*setContentView 可不写*/
//        setContentView(R.layout.activity_splash)
        /*创建与页面关联的SplashScreen实例*/
        installSplashScreen().apply {
    
    
            /*保持住启动页面的显示*/
            setKeepOnScreenCondition {
    
    
                keepOnScreenCondition.get()
            }
            /*指定是否Activity要自己处理启动画面动画 实际上就是keepOnScreenCondition的值为false时这个就会回调*/
            setOnExitAnimationListener {
    
    
                /*在这里我们可以弹窗让用户同意隐私政策*/
                val alertDialog = AlertDialog.Builder(this@SplashActivity)
                    .setTitle("隐私协议")
                    .setMessage("隐私协议内容")
                    .setPositiveButton(
                        "同意"
                    ) {
    
     dialog, which ->

                        /*跳转页面*/
                        val intent = Intent(this@SplashActivity, MainActivity::class.java)
                        startActivity(intent)
                    }
                    .setNegativeButton("拒绝") {
    
     dialog, which ->
                        this@SplashActivity.finish()
                    }.create();
                alertDialog.show();
            }

        }


        MainScope().launch {
    
    
            Log.i("SplashActivity", "可以做一些初始化逻辑")
            delay(500)
            keepOnScreenCondition.compareAndSet(true, false)
        }

    }
}

もう一度実行してみましょう:
画像の説明を追加してください

一部の端末でデバッグモード時にsetOnExitAnimationListenerがコールバックしない問題

楽しくコードを書いた後は問題ないと思ったのですが、実際の Android 12 端末に切り替えて実行してみると、起動ページで止まってしまって、ポップアップウィンドウもページジャンプも行われないことに気付きました。何度も試しましたが、やはり同じでした。
ログを追加したところ、setOnExitAnimationListener のコールバックが実行されていないことがわかりました。明らかに公式ドキュメントに従って書かれているのに、どうして問題が起きるのでしょうか?
ドキュメントをよく読むと、スプラッシュスクリーンが終了する前に setOnExitAnimationListener が設定されていることを確認する必要があると書かれていますが、私のコードは間違いなく問題ありません。

その後、アプリを手動で強制終了し、アイコンをクリックして手動で起動すると正常に戻りましたが、混乱したので情報を確認したところ、他の人もこの問題に遭遇していることがわかりました。

https://issuetracker.google.com/issues/197906327

この問題は Google 関係者によって予想どおりにマークされており、解決される予定はありません。
ここに画像の説明を挿入

意味:
これは意図的なものです。IDE は実際にインストルメンテーションを使用してアプリケーションを開くため、システムはこれを、ユーザーがランチャー アイコンをクリックするのではなく、あるアプリケーションが別のアプリケーションを開いていると解釈します。
そのため、setOnExitAnimationListener が実行されない状況が発生します。

デバッグ時に影響を受けるだけでなく、アプリは他の方法からも影響を受けます。たとえば、一部の rom はインストール後に自動的にアプリを開き、スタックします。正常に入るにはプロセスを強制終了して再起動する必要があります。
したがって、後続のコードがコールバックされsetOnExitAnimationListenerない。

一般的な考え方は、最後に実行されるメソッドにマークを追加しkeepOnScreenCondition.compareAndSet(true, false)、少し遅れて実行される最後のメソッドを呼び出して、確実に実行されるようにすることです。


サンプルコードは次のとおりです。

import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import com.yzq.kotlincommon.ui.activity.MainActivity
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import java.util.concurrent.atomic.AtomicBoolean

class SplashActivity : AppCompatActivity() {
    
    

    /**
     * 控制是否保持启动页面的变量,值为false时继续往下走
     */
    private val keepOnScreenCondition = AtomicBoolean(true)

    /*最终的方法是否调用*/
    private val dialogShowInvoke = AtomicBoolean(false)

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        /*setContentView 可不写*/
//        setContentView(R.layout.activity_splash)
        /*创建与页面关联的SplashScreen实例*/
        installSplashScreen().apply {
    
    
            /*保持住启动页面的显示*/
            setKeepOnScreenCondition {
    
    
                keepOnScreenCondition.get()
            }
            /*指定是否Activity要自己处理启动画面动画 实际上就是keepOnScreenCondition的值为false时这个就会回调*/
            setOnExitAnimationListener {
    
    
                /*在这里我们可以弹窗让用户同意隐私政策*/
                showDialog()
            }

        }


        MainScope().launch {
    
    
            Log.i("SplashActivity", "可以做一些初始化逻辑")
            /*解除blockui,此时正常情况下会调用setOnExitAnimationListener 已知Android12拉起App时不会调用*/
            keepOnScreenCondition.compareAndSet(true, false)
            delay(100)//这里最好延迟一下,保证setOnExitAnimationListener有机会得到执行
            if(!dialogShowInvoke.get()){
    
    
            	showDialog()//这里去掉调用一下最终要执行的方法,兜个底
            }
        }

    }

    @Synchronized
    private fun showDialog() {
    
    
        if (dialogShowInvoke.get()) {
    
    
            /*已经执行了*/
            return
        }
        dialogShowInvoke.compareAndSet(false, true)
        val alertDialog = AlertDialog.Builder(this@SplashActivity)
            .setTitle("隐私协议")
            .setMessage("隐私协议内容")
            .setPositiveButton(
                "同意"
            ) {
    
     dialog, which ->

                /*跳转页面*/
                val intent = Intent(this@SplashActivity, MainActivity::class.java)
                startActivity(intent)
            }
            .setNegativeButton("拒绝") {
    
     dialog, which ->
                this@SplashActivity.finish()
            }.create();
        alertDialog.show()
    }
}

このようにすることで、起動時に固まることはありませんが、Android 12 で他のアプリから呼び出されたときに、設定した UI が異常に表示され、見た目や操作感に影響を与える可能性があります。


この記事が役立つと思われる場合は、高評価をお願いします。より多くの開発者を助けることができます。記事に間違いがある場合は、修正してください。転載する場合は、Yu Zhiqiang のブログからの転載であることを明記してください。ありがとう_

おすすめ

転載: blog.csdn.net/yuzhiqiang_1993/article/details/128756426