137

众所周知,许多 Android 应用程序在首次Activity聚焦之前会非常短暂地显示白屏。在以下情况下会出现此问题:

  • Application扩展全局类并在其中执行主要初始化的 Android 应用程序。Application 对象总是在第一个对象之前创建(Activity可以在调试器中观察到的事实),所以这是有道理的。这就是我的案件延误的原因。

  • 在初始屏幕之前显示默认预览窗口的 Android 应用程序。

设置android:windowDisablePreview = "true"显然在这里不起作用。我也不能将启动画面的父主题设置Theme.Holo.NoActionBar此处所述,因为 [不幸] 我的启动画面使用ActionBar.

同时,不扩展Application类的应用程序在启动时不会显示白屏。

问题是,理想情况下,对象中执行的初始化Application需要在第一次显示之前Activity发生。所以我的问题是,如何在使用Application对象的情况下在应用启动时执行这些初始化?可能使用Threador Service,我想?

这是一个值得思考的有趣问题。我不能以通常的方式绕过它(通过设置NoActionBar主题),因为可悲的是,我的启动画面实际上是ActionBar由于一些不相关的原因。

笔记:

我已经提到了以下问题:

参考:

4

19 回答 19

117

请将此行添加到您的应用主题中

<item name="android:windowDisablePreview">true</item>

欲了解更多信息:https ://developer.android.com/topic/performance/vitals/launch-time#themed

于 2016-06-09T06:56:12.080 回答
98

白色背景的问题是由于android在应用加载到内存时冷启动引起的,可以通过以下方式避免:

public class OnboardingWithCenterAnimationActivity extends AppCompatActivity {
public static final int STARTUP_DELAY = 300;
public static final int ANIM_ITEM_DURATION = 1000;
public static final int ITEM_DELAY = 300;

private boolean animationStarted = false;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    setTheme(R.style.AppTheme);
    getWindow().getDecorView().setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_onboarding_center);
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {

    if (!hasFocus || animationStarted) {
        return;
    }

    animate();

    super.onWindowFocusChanged(hasFocus);
}

private void animate() {
    ImageView logoImageView = (ImageView) findViewById(R.id.img_logo);
    ViewGroup container = (ViewGroup) findViewById(R.id.container);

    ViewCompat.animate(logoImageView)
        .translationY(-250)
        .setStartDelay(STARTUP_DELAY)
        .setDuration(ANIM_ITEM_DURATION).setInterpolator(
            new DecelerateInterpolator(1.2f)).start();

    for (int i = 0; i < container.getChildCount(); i++) {
        View v = container.getChildAt(i);
        ViewPropertyAnimatorCompat viewAnimator;

        if (!(v instanceof Button)) {
            viewAnimator = ViewCompat.animate(v)
                    .translationY(50).alpha(1)
                    .setStartDelay((ITEM_DELAY * i) + 500)
                    .setDuration(1000);
        } else {
            viewAnimator = ViewCompat.animate(v)
                    .scaleY(1).scaleX(1)
                    .setStartDelay((ITEM_DELAY * i) + 500)
                    .setDuration(500);
        }

        viewAnimator.setInterpolator(new DecelerateInterpolator()).start();
    }
}
}

布局

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?colorPrimary"
android:orientation="vertical"
>

<LinearLayout
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:gravity="center"
    android:orientation="vertical"
    android:paddingTop="144dp"
    tools:ignore="HardcodedText"
    >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="16dp"
        android:alpha="0"
        android:text="Hello world"         android:textAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse"
        android:textColor="@android:color/white"
        android:textSize="22sp"
        tools:alpha="1"
        />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="8dp"
        android:alpha="0"
        android:gravity="center"
        android:text="This a nice text"
      android:textAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle.Inverse"
        android:textSize="20sp"
        tools:alpha="1"
        />

    <Button
        android:id="@+id/btn_choice1"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="48dp"
        android:scaleX="0"
        android:scaleY="0"
        android:text="A nice choice"
        android:theme="@style/Button"
        />

    <Button
        android:id="@+id/btn_choice2"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="4dp"
        android:scaleX="0"
        android:scaleY="0"
        android:text="Far better!"
        android:theme="@style/Button"
        />

</LinearLayout>

<ImageView
    android:id="@+id/img_logo"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:src="@drawable/img_face"
    tools:visibility="gone"
    />
</FrameLayout>

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
        android:opacity="opaque">

<item android:drawable="?colorPrimary"/>
<item>
    <bitmap
        android:gravity="center"
        android:src="@drawable/img_face"/>
</item>

将此主题添加到清单中的启动画面

<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:windowBackground">@null</item>
</style>

<style name="AppTheme.CenterAnimation">
    <item name="android:windowBackground">@drawable/ll_face_logo</item>
</style>

会产生这样的效果

一只忙碌的猫

有关更多详细信息和更多解决方案,您可以查看此 BlogPost

于 2016-06-07T12:11:11.223 回答
38

请将这两行复制并粘贴到您的清单应用程序主题中,即 res/styles/AppTheme。然后它会像魅力一样工作..

<item name="android:windowDisablePreview">true</item>
<item name="android:windowIsTranslucent">true</item>
于 2018-03-16T06:57:32.540 回答
35

答案中缺少解决此问题的推荐方法。所以我在这里添加我的答案。启动时出现白屏问题是因为系统进程在启动应用程序时绘制的初始空白屏幕。解决此问题的常用方法是通过将其添加到styles.xml文件中来关闭此初始屏幕。

<item name="android:windowDisablePreview">true</item>

但根据 android 文档,这可能会导致更长的启动时间。根据谷歌,避免这种初始白屏的推荐方法是使用活动的windowBackground主题属性并为启动活动提供一个简单的自定义可绘制对象。

像这样:

可绘制布局文件,my_drawable.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
  <!-- The background color, preferably the same as your normal theme -->
  <item android:drawable="@android:color/white"/>
  <!-- Your product logo - 144dp color version of your app icon -->
  <item>
    <bitmap
      android:src="@drawable/product_logo_144dp"
      android:gravity="center"/>
  </item>
</layer-list>

在您的环境中创造一种新风格styles.xml

<!-- Base application theme. -->
<style name="AppTheme">
    <!-- Customize your theme here. -->               
</style>

<!-- Starting activity theme -->
<style name="AppTheme.Launcher">
    <item name="android:windowBackground">@drawable/my_drawable</item>
</style>

将此主题添加到清单文件中的开始活动

<activity ...
android:theme="@style/AppTheme.Launcher" />

setTheme(R.style.Apptheme)当您想在通话之前转换回正常的主题通话时super.onCreate()setContentView()

public class MainActivity extends AppCompatActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    // Make sure this is before calling super.onCreate
    setTheme(R.style.Theme_MyApp);
    super.onCreate(savedInstanceState);
    // ...
  }
}

这是解决问题的推荐方法,来自谷歌材料设计模式。

于 2018-03-13T10:54:35.660 回答
21

首先,要删除白屏,请阅读此内容 - https://www.bignerdranch.com/blog/splash-screens-the-right-way/

但更重要的是,优化您的初始负载并将任何繁重的工作推迟到您有时间运行它的时候。如果您想让我们看一下,请在此处发布您的应用程序类。

于 2016-05-25T12:38:57.733 回答
19

您是否尝试过将android:windowBackground启动器活动主题中的属性设置为颜色或可绘制对象?

例如这个:

<item name="android:windowBackground">@android:color/black</item>

添加到 Launcher 活动主题后,启动时将显示黑色(而不是白色)。这是一个隐藏长时间初始化的简单技巧,同时向您的用户展示一些东西,即使您将 Application 对象子类化,它也可以正常工作。

避免使用其他构造(甚至线程)来执行长时间的初始化任务,因为您最终可能无法控制此类构造的生命周期。Application 对象是执行此类操作的正确位置。

于 2016-06-07T13:45:02.347 回答
17

我在styles.xml下的主题中添加了以下两行

    <item name="android:windowDisablePreview">true</item>
    <item name="android:windowBackground">@null</item>

像魅力一样工作

于 2019-01-28T08:06:46.033 回答
11

我有同样的问题,你必须更新你的风格。

样式.xml

<!-- Base application theme. -->
 <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

        <!-- Customize your theme here. -->
        <item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowDisablePreview">true</item>
        <item name="android:windowBackground">@null</item>
        <item name="android:windowIsTranslucent">true</item>

 </style>

您的清单文件应如下所示。

<application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
     // Other stuff
</application>

输出:

在此处输入图像描述

希望这会对你有所帮助。

于 2017-06-08T08:11:16.850 回答
7

在生命周期回调方法中,您可以声明当用户离开和重新进入活动时活动的行为方式。请记住,Android 的设计方式是每个应用程序都有一个生命周期。如果您对该方法(这是用于加载布局文件并初始化其中的任何控件的方法)施加过多负载onCreate(),则白屏将变得更加明显,因为布局文件将需要更长的时间来加载。

我建议在开始活动时使用几种不同的方法。这些是onStart()(在加载应用程序后作为第一件事调用),onActivityCreated()(在显示布局后调用,如果您在启动 Activity 时进行任何数据处理,则很有用)。

为了让你更容易,下面是官方的活动生命周期图:

在此处输入图像描述

于 2016-06-02T14:20:39.387 回答
3

请尝试一次。

  1. 创建一个可绘制文件 splash_background.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@color/{your color}" />

    <item>
        <bitmap
            android:layout_width="@dimen/size_250"
            android:layout_height="@dimen/size_100"
            android:gravity="center"
            android:scaleType="fitXY"
            android:src="{your image}"
            android:tint="@color/colorPrimary" />
    </item>

</layer-list>
  1. 把它放在styles.xml中

      <style name="SplashTheme" parent="Theme.AppCompat.NoActionBar">
          <item name="android:windowBackground">@drawable/splash_background</item>
      </style>
    
  2. 在您的 AndroidMainfest.xml 中,将上述主题设置为 Launch 活动。

        <activity
             android:name=".SplashScreenActivity"
             android:screenOrientation="portrait"
             android:theme="@style/SplashTheme"
             android:windowSoftInputMode="stateVisible|adjustResize">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
    
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
    
于 2019-07-18T08:47:06.090 回答
3

根据Google 的建议 Here,您不应阻止此白屏启动。您可以使用此主题属性来关闭系统进程在启动应用程序时绘制的初始空白屏幕。

<item name="android:windowDisablePreview">true</item>

但是,不建议使用此方法,因为它可能会导致比不抑制预览窗口的应用程序更长的启动时间。此外,它会迫使用户在活动启动时等待没有反馈,让他们怀疑应用程序是否正常运行。

他们建议使用活动的 windowBackground 主题属性为启动活动提供简单的自定义可绘制对象,而不是禁用预览窗口。

因此,这里是推荐的解决方案:

首先,创建一个新的可绘制文件,例如 startup_screen.xml

 <layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
    <!-- The background color, preferably the same as normal theme -->
    <item android:drawable="@android:color/white"/>
    <!-- Product logo - 144dp color version of App icon -->
    <item>
        <bitmap
            android:src="@drawable/logo"
            android:gravity="center"/>
    </item>
 </layer-list>

其次,从您的样式文件中引用它。如果您使用夜间模式。在两个themes.xml 文件中添加它。

<!-- Start Up Screen -->
<style name="AppThemeLauncher" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
     <item name="android:statusBarColor" tools:targetApi="l">@color/lightGray</item>
     <item name="android:windowBackground">@drawable/startup_screen</item>
</style>

如果您注意到,我添加了 statusBarColor 属性来根据我的自定义设计更改状态栏的颜色。

然后,在您当前的活动中添加AppThemeLauncher主题。

<activity
    android:name=".MainActivity"
    android:theme="@style/AppThemeLauncher"/>

如果您想转换回您的正常主题,请在调用 super.onCreate() 和 setContentView() 之前调用 setTheme(R.style.AppTheme):

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        // Make sure this is before calling super.onCreate
        setTheme(R.style.AppTheme)
        super.onCreate(savedInstanceState)
        // ...
    }
}
于 2021-10-21T02:40:57.710 回答
2

您是否尝试过初始化onActivityCreated

课内Application

 registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                if(activity.getClass().equals(FirstActivity.class) {
                    // try without runOnUiThread if it will not help
                    activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            new InitializatioTask().execute();
                        }
                    });
                }
            }

            @Override
            public void onActivityStarted(Activity activity) {

            }

            @Override
            public void onActivityResumed(Activity activity) {

            }

            @Override
            public void onActivityPaused(Activity activity) {

            }

            @Override
            public void onActivityStopped(Activity activity) {

            }

            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

            }

            @Override
            public void onActivityDestroyed(Activity activity) {

            }
        });
于 2016-06-02T10:05:58.700 回答
2

由于您已经知道为什么会出现此白屏,原因是后台进程或应用程序初始化或大文件,因此只需检查以下想法以解决此问题。

为了防止应用程序开始出现此白屏,一种方法是启动屏幕,这只是一种非最终方法,您必须使用。

当您从 splash.xml 文件显示启动画面时,此问题也将保持不变,

因此,您必须在 style.xml 文件中为启动画面创建 ont 样式,并且必须将窗口背景设置为启动图像,然后将该主题应用于清单文件中的启动活动。所以现在当你运行应用程序时,首先它会设置主题,通过这种方式用户将能够直接看到启动图像而不是白屏。

于 2016-06-02T10:06:02.543 回答
2

两个属性都有效

    <style name="AppBaseThemeDark" parent="@style/Theme.AppCompat">
            <!--your other properties -->
            <!--<item name="android:windowDisablePreview">true</item>-->
            <item name="android:windowBackground">@null</item>
            <!--your other properties -->
    </style>
于 2016-08-18T09:06:37.113 回答
1

对于调试时出现白屏的任何人,请注意,如果您正在调试,则加载时间会更长。如果您构建发布版 APK 并将其安装在手机上,您会注意到加载所需的时间要少得多。

所以调试版本的启动时间不等于发布版本的启动时间。

于 2020-03-23T11:48:17.597 回答
0

只需在 values/styles.xml 中写入项目:

<item name="android:windowBackground">@android:color/black</item>

例如,在 AppTheme 中:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="windowNoTitle">true</item>
    <item name="windowActionBar">false</item>
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowContentOverlay">@null</item>

    <item name="android:windowBackground">@android:color/black</item>

    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>
于 2017-04-02T07:33:45.143 回答
0
Style :- 
<style name="SplashViewTheme" parent="Theme.AppCompat.NoActionBar">
    <item name="android:windowBackground">@drawable/splash</item>
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
</style>

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

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
于 2018-07-06T07:02:26.373 回答
0

删除

<style name="AppTheme.Launcher">
    <item name="android:windowBackground">@drawable/splashscreen</item>
</style>

来自 style.xml 文件

于 2021-06-29T11:27:30.677 回答
0

您应该colors.xml在 values-night (如果它尚不存在,则在 values 文件夹旁边创建)文件夹用于深色主题颜色。例如。

<resources>
    <color name="status_bar">#0e0e0e</color>
</resources>

colors.xml常规值文件夹将用于轻主题)

styles.xml哪个为您的应用程序主题提供背景和状态栏时,您将获得必要的值。例如。

<style name="Theme.<AppName>" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/red700</item>
        <item name="colorPrimaryDark">@color/red900</item>
        <item name="colorAccent">@color/red700</item>
        <item name="android:statusBarColor">@color/status_bar</item>
        <item name="android:background">@color/status_bar</item>
    </style>

AndroidManifest.xml 文件中引用了此样式

android:theme="@style/Theme.<AppName>">
于 2022-02-17T05:08:09.423 回答