Android-启动时防止出现白屏

众所周知,许多 Android 应用程序在其第一个 Activity成为焦点之前都会非常短暂地显示白色屏幕。在下列情况下可以看到这个问题:

  • 扩展全球 Application类和 执行其中的主要初始化 对象总是在第一个 Activity之前创建(这个事实可以 在调试器中被观察到) ,所以这是有意义的,这就是在我的例子中出现延迟的原因。

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

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

同时,没有扩展 Application不要的应用程序在启动时显示白色屏幕。

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

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

注:

我已经提到以下问题:

参考文献:

107755 次浏览

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

但是更重要的是,优化您的初始负载并将任何繁重的工作推迟到您有时间运行它的时候。如果你想让我们看看的话,可以把你的申请类贴在这里。

你试过把初始化设置为 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) {


}
});

正如你已经知道为什么这个白色屏幕存在,由于后台进程或应用程序初始化或大文件,所以只是检查下面的想法,以克服这一点。

为了防止这个白色的屏幕在应用程序的开始,一种方法是启动画面,这只是一种方法不是最终的,你必须使用。

当您显示 splash.xml 文件中的启动画面时,这个问题也将保持不变,

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

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

我建议在开始一项活动时使用几种不同的方法。比如 onStart()(在应用程序加载后被作为第一个调用) ,onActivityCreated()(在布局显示后被调用,如果您在开始活动时进行任何数据处理,那么 onActivityCreated()非常有用)。

为了方便您,下面是正式的活动生命周期图(来自 http://web.archive.org/web/20140218132043/http://developer.android.com/training/basics/activity-lifecycle/starting.html) :

enter image description here

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

会产生这样的效果

a busy cat

更多的细节和更多的解决方案,您可以检查这一点 BlogPost 博客

你有没有试过设置 android:windowBackground属性在你的启动器活动的主题,无论是一种颜色或绘制?

例如:

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

当添加到 Launcher 活动主题时,启动时将显示黑色(而不是白色)。这是一个隐藏长初始化的简单技巧,同时向用户显示一些东西,即使您子类化了 Application 对象,也可以显示 而且效果很好

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

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

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

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

两种属性都有效

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

只需在 value/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>

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

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>

外景:

enter image description here

希望这个能帮到你。

推荐的解决这个问题的方法在答案中缺失。所以我在这里加上我的答案。启动时的白屏问题是由于系统进程在启动应用程序时绘制的初始空白屏幕造成的。解决这个问题的一个常见方法是通过将其添加到 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>

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

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

当您想要转换回正常的主题时,在调用 super.onCreate()setContentView()之前先调用 setTheme(R.style.Apptheme)

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);
// ...
}
}

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

请复制并粘贴这两行在您的清单应用程序主题,即 res/style/AppTheme。然后它会像魅力。

<item name="android:windowDisablePreview">true</item>
<item name="android:windowIsTranslucent">true</item>
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>

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

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

非常有效

请再试一次。

  1. 创建一个可绘制的文件 splash _ backing.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>
    

对于那些在调试时拥有白屏的人,请注意,如果您正在进行调试,那么加载将花费更长的时间。如果您建立您的发行版 APK,并安装在您的手机上,您会注意到,它需要很少的加载。

因此,使用调试版本的启动时间不等于使用发布版本的启动时间。

删除

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

来自 style.xml 文件

根据 谷歌的推荐 给你,你 不应该防止这个白色屏幕启动。您可以使用这个主题属性来关闭系统进程在启动应用程序时绘制的初始空白屏幕。

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

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

他们建议使用活动的 windows 背景主题属性为开始的活动提供一个简单的自定义绘图,而不是禁用预览窗口。

因此,建议采取以下解决方案:

首先,创建一个新的可绘制文件,例如 start _ 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>

其次,从样式文件中引用它。如果使用 Night 模式,请将它添加到两个 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)
// ...
}
}

您应该有 colors.xml的值-夜晚(创建旁边的值文件夹,如果它不已经存在)文件夹为深色主题颜色。 例如。

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