Java Android - 防止启动时出现白屏

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37437037/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 19:20:39  来源:igfitidea点击:

Android - Prevent white screen at startup

javaandroidmultithreadingperformancecold-start

提问by Y.S

As we all know, many Android apps display a white screen very briefly before their first Activitycomes into focus. This problem is observed in the following cases:

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

  • Android apps that extend the global Applicationclass and perform major initializations therein. The Applicationobject is always created before the first Activity(a fact that can be observed in the debugger), so this makes sense. This is the cause of the delay in my case.

  • Android apps that display the default preview window before the splash screen.

  • 扩展全局Application类并在其中执行主要初始化的Android 应用程序。的Application对象总是之前首先创建的Activity(即可以在调试器中观察到的事实),所以这是有意义的。这就是我的情况延迟的原因。

  • 在启动画面之前显示默认预览窗口的 Android 应用程序。

Setting android:windowDisablePreview = "true"obviously does not work here. Nor can I set the parent theme of the splash screen to Theme.Holo.NoActionBaras described here, because [unfortunately] my splash screen makes use of an ActionBar.

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

Meanwhile, apps that do not extend the Applicationclass do notshow the white screen at startup.

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

The thing is, ideally the initializations performed in the Applicationobject need to occur beforethe first Activityis shown. So my question is, how can I perform these initializations on app startup withoutusing an Applicationobject? Possibly using a Threador Service, I suppose?

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

This is an interesting problem to think about. I can't bypass it the usual way (by setting the NoActionBartheme), as tragically my Splash screen actually has an ActionBardue to some unrelated reasons.

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

Note:

笔记:

I have already referred to the following questions:

我已经提到了以下问题:

References:

参考:

采纳答案by Ivan Milisavljevic

The problem with white background is caused because of android's cold start while the app loads to memory, and it can be avoided with this:

白色背景的问题是由于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();
    }
}
}

layout

布局

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

头像

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

Add this theme to your splashscreen in the manifest

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

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

which will produce efect like this

这将产生这样的效果

a busy cat

一只忙碌的猫

for more details and more solutions you can check this BlogPost

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

回答by Shmuel

First of all, to remove the white screen read this - https://www.bignerdranch.com/blog/splash-screens-the-right-way/

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

But more importantly, optimize your initial load and defer any heavy work to when you have time to run it. Post your application class here if you want us to take a look at it.

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

回答by Sergey Shustikov

Did you try to put initialization to onActivityCreated?

您是否尝试将初始化设置为onActivityCreated

Inside Applicationclass :

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

            }
        });

回答by Vickyexpert

As you are already aware why this white screen is there, as due to background processes or application initialization or large files, so just check below idea for overcome from this.

由于您已经知道为什么会出现这个白屏,因为后台进程或应用程序初始化或大文件,因此请查看以下想法以克服此问题。

To prevent this white screen on beginning of the app, one way is splash screen, this is just a way not final and you must have to use.

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

When you will show splash screen from your splash.xml file, then also this issue will be remain same,

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

So you have to create ont style in style.xml file for splash screen and there you have to set window background as your splash image and then apply that theme to your splash activity from manifest file. So now when you will run app, first it will set theme and by this way user will be able to see directly splash image instead of white screen.

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

回答by Michele La Ferla

Within the lifecycle callback methods, you can declare how your activity behaves when the user leaves and re-enters the activity. Remember that the way Android is designed, there is a lifecycle for each and every app. If you put too much load to the onCreate()method (which is the method used to load the layout files and initalise any controls you have in it), then the white screen will become more visible, as the layout file will take longer to load.

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

I suggest using several different methods when starting an activity. Such are the onStart()(being called as the first thing once the app is loaded), onActivityCreated()(being called after the layout is displayed and useful if you are making any data processing upon starting the activity).

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

To make it easier for you, below is the official activity lifecycle diagram:

为了方便您,下面是官方的活动生命周期图:

enter image description here

在此处输入图片说明

回答by gmetal

Have you tried setting theandroid:windowBackgroundattribute in the theme of your launcher activity, to either a color or a drawable?

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

For example this:

例如这个:

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

when added to the Launcher activity theme will show a black color (rather than the white color) on startup. This is an easy trick to hide long initialisation, while showing your users something, and it works fineeven if you subclass the Application object.

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

Avoid using other constructs (even Threads) for doing long initialisation tasks, because you may end up not being able to control the lifecycle of such constructs. The Application object is the correct place for doing exactly this type of actions.

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

回答by Hitesh Singh

please add this line into your app theme

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

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

for more information : https://developer.android.com/topic/performance/vitals/launch-time#themed

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

回答by Sohail Zahid

Both properties works

两个属性都有效

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

回答by Javier Reinoso

Just write the item in values/styles.xml:

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

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

For example, in the AppTheme:

例如,在 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>

回答by Hiren Patel

I had same issue, you have to update your style.

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

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>

Your manifest file should looks like below.

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

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

Outout:

输出:

enter image description here

在此处输入图片说明

Hope this would help you.

希望这会帮助你。