Android-防止启动时出现白屏


110

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

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

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

设置android:windowDisablePreview = "true"显然在这里不起作用。我也无法将初始屏幕的父主题设置Theme.Holo.NoActionBar此处所述,因为[不幸的是]我的初始屏幕使用了ActionBar

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

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

这是一个有趣的问题。我无法以通常的方式绕过它(通过设置NoActionBar主题),因为可悲的是我的启动画面实际上ActionBar由于某种不相关的原因而出现故障。

注意:

我已经提到以下问题:

参考文献:


1
您自己发现了问题,并且在应用程序上下文中对许多init进行了操作,阻止了活动的加载,尝试使此操作异步化,直到某些线程结束为止,使加载活动显示出来。
AxelH

可能会有所帮助
Max

1
理想情况下,应用程序将卸载处理,并且不使用主线程进行长时间操作。这是一个公认的做法。如果操作需要在应用加载之前发生,则它至少应不与UI共享线程。
Beshoy Hanna

1
将所有初始化代码移出Application类后,您可能会发现这仍然是一个问题。这是由于更新版本的Android“冷启动”应用程序的方式。Google实际上在今年解决了Google I / O的启动时间,根据我的记忆,它将以N固定。同时,您应该看一下Google所谓的“品牌启动屏幕”。这是一个有关如何创建它的示例:antonioleiva.com/branded-launch-screen-开始时不要再有白屏了;-)而且请不要使用启动屏-这对用户来说很烦人。
达尔文'16

1
Wrt主题,诀窍不是设置NoActionBar主题,而是调整初始活动的主题,以使空白主题屏幕看起来像完全初始化的主题屏幕。
zapl

Answers:


86

白色背景的问题是由于在应用程序加载到内存时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>

img脸

<?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


3
它最终还是没有帮助白屏和动画
Mehvish Ali

这是直接的实现。您的代码中可能还有其他一些部分导致了此问题。请提出另一个问题,我将在那里为您提供帮助:)
Ivan Milisavljevic

1
我通过在主题之间进行动画处理并更改主题(没有可绘制的对象,而只是使用相同的背景色)来解决此问题,然后在onWindowFocusChanged()上将内容可视化,并以其他方式使它动画化,在过渡之间也进行了变白。主题动画
大有


33

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

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


19

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

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

但是根据android文档,这可能会导致更长的启动时间。根据Google避免此初始白屏的建议方法是使用活动的windowBackgroundtheme属性,并为开始的活动提供一个简单的自定义可绘制对象。

像这样:

可绘制布局文件, 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);
    // ...
  }
}

这是解决问题的推荐方法,它来自google Material Design模式。


14

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

例如:

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

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

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


14

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

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

像魅力一样工作


10

我遇到了同样的问题,您必须更新自己的样式。

style.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>

外出:

在此处输入图片说明

希望这对您有帮助。


2
在NativeActivity OpenGL应用程序上,这对我来说非常有用。我不知道为什么这不是最完整,最方便的答案,所以在答案中没有做到更高。没有Java涉及几个XML文件更改。
斯莱恩

7

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

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

为了让您更轻松,下面是官方活动生命周期图:

在此处输入图片说明


谢谢您的回答,这非常有趣。但是,我相信您误解了我的问题。问题不是由first中的初始化引起的Activity,而是全局Application对象中的初始化引起的。而且我不相信我可以在这里将关注点分离开来,因为与Activity单独的关注点只有一种onCreate()方法。
YS

为什么要扩展应用程序类而不是活动类?
Michele La Ferla

好的,所以您的意思是我应该Application完全放弃该对象,并将所有初始化代码移至第一个Activity...
YS

这就是我一直开发应用程序的方式,但是,如果您不希望进行所有这些更改,则其他答案可能会帮助您使用应用程序类解决问题。为了将来参考,我建议立即使用一个活动类,然后再使用许多片段。希望这会
有所

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) {

            }
        });

2

如您所知,由于后台进程或应用程序初始化或文件过大,为什么会有白屏出现,因此请检查以下想法以解决此问题。

为了防止在应用程序启动时出现白屏,一种方法是启动屏幕,这不是最终的方法,必须使用。

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

因此,您必须在初始屏幕的style.xml文件中创建on样式,然后在其中将窗口背景设置为初始图像,然后将该主题应用于清单文件中的初始活动。因此,现在当您运行应用程序时,它将首先设置主题,这样用户将可以直接看到初始图像而不是白屏。


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>

2

请尝试一次。

1)创建一个可绘制文件splash_background.xml

<?xml version="1.0" encoding="utf-8"?>
<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>

2)放入styles.xml

     <style name="SplashTheme" parent="Theme.AppCompat.NoActionBar">
         <item name="android:windowBackground">@drawable/background_splash</item>
     </style>

3)在您的AndroidMainfest.xml中,将上述主题设置为启动活动。

       <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>

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>

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>

0

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

因此,debbug版本的启动时间不等于发行版的启动时间。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.