Android 冷启动黑/白屏 or“两个启动屏幕(SplashActivity)?”or“多了一个含有app icon的启动页面”

嘿嘿,你好啊

说起来,这是一个咱们Android开发中,非常经典的一个问题,通常就是叫"冷启动白屏/黑屏问题"(Cold Start White/Black Screen)。然后看到的第一个"新加的页面",其实并不是咱们开发者主动增加的activity,而是Android系统给自动生成的"预览窗口"(Starting Window)。

1.为啥会出现这个页面

当用户点击app图片来启动App时,我们都知道Android系统需要做很多准备工作,如加载app进程、加载DEX文件、初始化application等等,这个过程是需要一定的加载时间的,通常就是几十毫秒到几秒。

然后呢,Android系统为了不让用户觉得点击图标后手机"死机"了或者没反应,系统就会立即弹出一个预览窗口,用来先及时响应一下用户的指令

2.效果图

原始效果

方案2效果:

方案3效果:

3.为啥标题这么长

哈哈哈哈,搞这么长个题目,实在也是属于无奈之举。因为国内厂商系统碎片化严重,各种厂商的各种定制系统,例如:小米的MIUI、HyperOS,oppo的ColorOS,华为的HarmonyOS等等。导致对Android系统来说是同一个问题的东西,在不同的厂商手机上,可能会有不一样的表现。

如果不做任何适配,比方说(目前发现问题的),

  • OPPO:可能是他们为了提升用户体验,然后系统自动检测咱们项目中的APP图标,然后给放到预览窗口的中间,模仿一个启动页,所以就有了最后一个"or"
  • 其他:其他的手机就是根据默认的主题背景色,然后会有一个白屏或者黑屏的显示

4.最佳解决方案:无缝过渡(Themed Launch Screen)

首先哈,建议不要试图去"消除"这个窗口(就比如说,你如果把这个预览窗口设为透明,那样确实不会有白屏黑屏啥的了,但是用户点击icon后,会感觉手机卡顿了一下才出现了你的SplashActivity,对于体验来说,甚至不如有个白屏了)。

经多对市场上的一些热门app的体验调研,我发现现在市面上大概有三种情况,

  1. 第一种就是先不管,点一下有个白屏,全部交给系统
  2. 第二种是设计一个背景色,然后加一个自己的logo,相当于简单自定义一下这个页面,更价贴合app主题
  3. 第三种则是将startingwindow直接替换成一整张图片

第一种肯定不用管,首先我们先说一下第二种,实现完毕之后就是:

点击icon ->瞬间展示贴合主题的页面->然后代码逻辑开始运行了,体验很丝滑美妙

ffs

  1. 第一步:添加依赖(build.gradle)
    在 app/build.gradle 文件中添加库的依赖:
xml 复制代码
dependencies {
    implementation "androidx.core:core-splashscreen:1.0.1"
}
  1. 第二步:配置主题 (themes.xml)
    咱们需要自定义一个专门的启动主题。这个主题用来自定义启动页长什么样
    打开 res/values/themes.xml (或 styles.xml):
xml 复制代码
    <style name="Theme.App.Starting" parent="Theme.SplashScreen">
<!--        背景色-->
        <item name="windowSplashScreenBackground">@color/white</item>
<!-- 背景中间的的图片-->
        <item name="windowSplashScreenAnimatedIcon">@drawable/startcenter</item>
<!--启动页结束后」,App 主界面要切换到的目标主题-->
        <item name="postSplashScreenTheme">@style/Theme.YourApp.Normal</item>
    </style>

    <style name="Theme.YourApp.Normal" parent="Theme.MaterialComponents.DayNight.NoActionBar">
        <item name="colorPrimary">@color/purple_500</item>
    </style>
  1. 第三步:修改 AndroidManifest.xml
    将项目中的入口activity,我的demo中是SplashActivity的主题,替换成咱们上面上自定义的主题
xml 复制代码
 <activity
            android:name=".ui.startingwindow.SplashActivity"
            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>
  1. 第四步:运行
    嘿嘿嘿,逗你玩儿,这个时候你会惊喜的发现,诶?startwindow设置明白了,怎么报错呢?欲知为何报错,请看下章第五步
xml 复制代码
  java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.blogdemoapplication/com.example.blogdemoapplication.ui.startingwindow.SplashActivity}: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
                                                                                                    	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4410)
                                                                                                    	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4631)
                                                                                                    	at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:112)
                                                                                                    	at android.app.servertransaction.TransactionExecutor.executeNonLifecycleItem(TransactionExecutor.java:186)
                                                                                                    	at android.app.servertransaction.TransactionExecutor.executeTransactionItems(TransactionExecutor.java:112)
                                                                                                    	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:84)
                                                                                                    	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2873)
                                                                                                    	at android.os.Handler.dispatchMessage(Handler.java:107)
                                                                                                    	at android.os.Looper.loopOnce(Looper.java:249)
                                                                                                    	at android.os.Looper.loop(Looper.java:337)
                                                                                                    	at android.app.ActivityThread.main(ActivityThread.java:9580)
                                                                                                    	at java.lang.reflect.Method.invoke(Native Method)
                                                                                                    	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593)
                                                                                                    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
                                                                                                    Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
                                                                                                    	at androidx.appcompat.app.AppCompatDelegateImpl.createSubDecor(AppCompatDelegateImpl.java:902)
                                                                                                    	at androidx.appcompat.app.AppCompatDelegateImpl.ensureSubDecor(AppCompatDelegateImpl.java:865)
                                                                                                    	at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:748)
                                                                                                    	at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:193)
                                                                                                    	at com.example.blogdemoapplication.ui.startingwindow.SplashActivity.onCreate(SplashActivity.kt:21)
                                                                                                    	at android.app.Activity.performCreate(Activity.java:9221)
                                                                                                    	at android.app.Activity.performCreate(Activity.java:9177)
                                                                                                    	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1538)
                                                                                                    	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4392)
                                                                                                    	... 13 more
  1. 在代码中初始化
    这是最重要的一步。你必须在 super.onCreate() 之前调用 installSplashScreen()。

kotlin:

xml 复制代码
 override fun onCreate(savedInstanceState: Bundle?) {
        val splashScreen = installSplashScreen()

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
       
        // ... 你的初始化代码
    }

下面是咱们用java的同学看的:

xml 复制代码
protected void onCreate(Bundle savedInstanceState) {
        SplashScreen splashScreen = SplashScreen.installSplashScreen(this);

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // ...你的初始化代码
    }

问题是解决了,那么有些喜欢观察的兄弟们说了, 我咋看有的app直接就是一个中间图片,然后底部还有个他们的Slogan啊,这博主藏着掖着的,不好好写是吧。别着急,兄弟们,没上来就说,其实是因为,底部添加图片的话,会在Android12上下有一个兼容性限制,比方说:

  • 新手机(Android 12+):显示中间Logo+底部图片
  • 旧手机(Android 11-):只显示中间Logo,底部图片会被自动忽略

如果能接受这种差异的话(当然凡是底部有图片的,也都是这么做的),请看下面详情解析:

  1. 首先你需要准备一张图片(建议是透明背景的PNG或SVG),我是demo只是为了展示功能。因为这个新的配置是Android12+的,所以你需要在values的同级目录新建一个values-v31,然后再创建一个themes.xml(styles.xml),原来themes.xml中的不变:
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="Theme.App.Starting" parent="Theme.SplashScreen">
        <!--        背景色-->
        <item name="windowSplashScreenBackground">@color/white</item>
        <!-- 背景中间的的图片-->
        <item name="windowSplashScreenAnimatedIcon">@drawable/startcenter</item>
        <!-- 背景底部的的图片-->
        <item name="android:windowSplashScreenBrandingImage">@drawable/startingbom</item>
        <!--启动页结束后」,App 主界面要切换到的目标主题-->
        <item name="postSplashScreenTheme">@style/Theme.YourApp.Normal</item>
    </style>
</resources>
复制代码
注意:
 对图片的一些要求:如果底部这张图太大,系统就可能不显示或者裁剪的及其难看,查了一些资料,看到推荐尺寸是:高度不要超过80dp,宽度不超过200dp,长宽比建议是2.5:1,内功的话,不要有太多透明边距

方案2终于是告一断落,接下来我们说一下方案3,看过官方文档并且细心的小伙伴应该能发现,理论上来说,绝对的替换成一张图片,Google是不支持的,因为官方最新标准,新 Splash API (core-splashscreen) 强制规定背景只能是颜色,不能是图片。并且中间必须是 Icon。所以理论上来说,方案3是不可行的。

但是虽然Google强推新标准,但是国内厂商(小米,OPPO,华为等)的ROM对"传统方式"的兼容性很好,为了视觉效果,国内很多app就依旧使用的传统方案。即:android:windowBackground 来设置背景图片,接下来说说完整步骤:

  1. 搞一张背景图
    起个名字,比如说splashbg.png,放到drawable目录下面
  2. 定义传统 Splash 主题
    在 themes.xml 中定义一个主题,然后将上面提到的 windowBackground 设为图片,并将状态栏设为透明以实现沉浸式效果
xml 复制代码
    <style name="Theme.App.FullSplash" parent="Theme.MaterialComponents.Light.NoActionBar">
<!--        背景图-->
        <item name="android:windowBackground">@drawable/splashbg</item>

        <item name="android:statusBarColor">@android:color/transparent</item>
        <item name="android:windowTranslucentStatus">true</item> </style>
  1. 应用到 Activity
xml 复制代码
<activity
            android:name=".ui.startingwindow.SplashActivity"
            android:exported="true"
            android:theme="@style/Theme.App.FullSplash">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

这就是背景是一整张图片的实现方案了,上面也说了,国内厂商兼容的挺好,但是就意味着,在原生 Android 12+如Pixel 手机上就会失效,然后变成纯色+logo的效果,看能不能接受了。

我是入梦,谢谢你的观看我的博客,觉着好用的话,麻烦帮忙点个赞呗,谢谢啦~ 如果有什么错误,请随时联系我噢~QQ:897589417

相关推荐
安卓理事人42 分钟前
安卓临时缓存sp工具类
android·缓存
r***01381 小时前
SpringBoot3 集成 Shiro
android·前端·后端
h***34631 小时前
SpringBoot3.3.0集成Knife4j4.5.0实战
android·前端·后端
j***57681 小时前
MySQL——表操作及查询
android·mysql·adb
轻口味1 小时前
基于Rokid Glasses的AI助盲应用实践:让科技点亮视障者的世界
android
j***89462 小时前
MySQL数据的增删改查(一)
android·javascript·mysql
小画家~2 小时前
第三十四:golang 原生 pgsql 对应操作
android·开发语言·golang
r***18642 小时前
FlinkCDC实战:将 MySQL 数据同步至 ES
android·mysql·elasticsearch
p***62992 小时前
mysql-connector-java 和 mysql-connector-j的区别
android·java·mysql