Android - 启动时防止白屏

Y.S*_*Y.S 94 java performance multithreading android cold-start

众所周知,许多Android应用在首次Activity关注之前会非常简短地显示白屏.在以下情况中会出现此问题:

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

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

设置android:windowDisablePreview = "true"显然在这里不起作用.我也不能Theme.Holo.NoActionBar这里描述的那样将启动画面的父主题设置为,因为[不幸的是]我的启动画面使用了一个ActionBar.

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

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

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

注意:

我已经提到了以下问题:

参考文献:

Iva*_*vic 75

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

布局

<?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>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

将此主题添加到清单中的初始屏幕

<?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>
Run Code Online (Sandbox Code Playgroud)

这将产生这样的效果

一只忙碌的猫

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

  • 它最终还没有帮助白屏和动画 (2认同)

Hit*_*ngh 64

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

<item name="android:windowDisablePreview">true</item>
Run Code Online (Sandbox Code Playgroud)

  • 它挂起应用程序2秒然后启动应用程序,对我没用! (12认同)
  • 现在它没有显示#ffffff颜色,但它现在显示#000000 (3认同)

小智 24

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

<item name="android:windowDisablePreview">true</item>
<item name="android:windowIsTranslucent">true</item>
Run Code Online (Sandbox Code Playgroud)


Shm*_*uel 18

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

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


gme*_*tal 10

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

例如:

<item name="android:windowBackground">@android:color/black</item>
Run Code Online (Sandbox Code Playgroud)

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

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

  • 最佳答案,不要忘记添加黑色主题,而不仅仅是白色) (2认同)

Aka*_*ava 10

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

    <item name="android:windowDisablePreview">true</item>
    <item name="android:windowBackground">@null</item>
Run Code Online (Sandbox Code Playgroud)

像魅力一样运作


Sam*_*Sam 9

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

<item name="android:windowDisablePreview">true</item>
Run Code Online (Sandbox Code Playgroud)

但是根据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>
Run Code Online (Sandbox Code Playgroud)

在您的商店中创建新样式 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>
Run Code Online (Sandbox Code Playgroud)

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

<activity ...
android:theme="@style/AppTheme.Launcher" />
Run Code Online (Sandbox Code Playgroud)

而当您想转换回常规主题通话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);
    // ...
  }
}
Run Code Online (Sandbox Code Playgroud)

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


Hir*_*tel 8

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

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>
Run Code Online (Sandbox Code Playgroud)

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

<application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
     // Other stuff
</application>
Run Code Online (Sandbox Code Playgroud)

Outout:

在此输入图像描述

希望这会对你有所帮助.

  • 这对我来说非常适合NativeActivity OpenGL应用程序.我不确定为什么这不是答案中的更高,因为它是最完整和最便捷的答案.没有Java只涉及几个XML文件更改. (2认同)

Mic*_*rla 7

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

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

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

在此输入图像描述