Android: evita la pantalla blanca al inicio

110

Como todos sabemos, muchas aplicaciones de Android muestran una pantalla en blanco muy brevemente antes de que Activityse enfoque la primera . Este problema se observa en los siguientes casos:

  • Aplicaciones de Android que amplían la Applicationclase global y realizan importantes inicializaciones en ella. El Application objeto siempre se crea antes que el primero Activity(hecho que se puede observar en el depurador), por lo que esto tiene sentido. Esta es la causa del retraso en mi caso.

  • Aplicaciones de Android que muestran la ventana de vista previa predeterminada antes de la pantalla de presentación.

La configuración android:windowDisablePreview = "true"obviamente no funciona aquí. Tampoco puedo configurar el tema principal de la pantalla de inicio Theme.Holo.NoActionBarcomo se describe aquí , porque [desafortunadamente] mi pantalla de inicio utiliza un archivo ActionBar.

Mientras tanto, las aplicaciones que no amplían la Applicationclase no muestran la pantalla blanca al inicio.

La cuestión es que, idealmente, las inicializaciones realizadas en el Applicationobjeto deben ocurrir antes de queActivity se muestre la primera . Entonces, mi pregunta es, ¿cómo puedo realizar estas inicializaciones al iniciar la aplicación sin usar un Applicationobjeto? Posiblemente usando un Threado Service, supongo.

Este es un problema interesante en el que pensar. No puedo omitirlo de la forma habitual (configurando el NoActionBartema), ya que, trágicamente, mi pantalla de bienvenida tiene un efecto ActionBardebido a algunas razones no relacionadas.

Nota:

Ya me he referido a las siguientes preguntas:

Referencias:

YS
fuente
1
Encontraste el problema tú mismo, estás haciendo muchos inicios en el contexto de la aplicación, bloqueando la carga de la actividad, intenta asincronizar esto, dejando que se muestre una actividad de carga hasta que termine algún hilo.
AxelH
Esto podría ayudar
Máximo
1
Idealmente, una aplicación descargaría el procesamiento y no usaría el hilo principal para operaciones largas. Ésta es una práctica bien aceptada. Si las operaciones deben realizarse antes de que se cargue la aplicación, al menos no debería compartir un hilo con la interfaz de usuario.
Beshoy Hanna
1
Es posible que descubra que esto sigue siendo un problema después de haber sacado todo el código de inicialización de la Applicationclase. Esto se debe a las versiones más recientes de la forma de Android de "iniciar en frío" las aplicaciones. Google realmente abordó los tiempos de lanzamiento en Google I / O este año y se arreglará en N según lo que recuerdo. Mientras tanto, debería mirar lo que Google llama una "pantalla de inicio de marca". Aquí hay un ejemplo sobre cómo crearlo: antonioleiva.com/branded-launch-screen - no más pantalla en blanco al principio ;-) Y por favor no use pantallas de bienvenida - es molesto para el usuario.
Darwind
1
Wrt tema, el truco no es establecer un tema NoActionBar, es ajustar el tema de la actividad inicial para que una pantalla temática vacía se vea como la totalmente inicializada.
zapl

Respuestas:

86

El problema con el fondo blanco se debe al inicio en frío de Android mientras la aplicación se carga en la memoria, y se puede evitar con esto:

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();
    }
}
}

diseño

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

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

Agregue este tema a su pantalla de presentación en el manifiesto

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

que producirá un efecto como este

un gato ocupado

Para obtener más detalles y más soluciones, puede consultar este BlogPost

Ivan Milisavljevic
fuente
3
no ayudó la pantalla en blanco y la animación al final
Mehvish Ali
Esta es una implementación sencilla. Puede haber otras partes de su código que causen el problema. Abra otra pregunta y estaré allí para ayudarlo :)
Ivan Milisavljevic
1
Resolví este problema animando entre temas y cambiando el tema sin dibujar, solo el color de fondo y luego en onWindowFocusChanged () enfureció el contenido visible y el animado, de lo contrario, también lo hice entre la transición. La animación de temas ayudó mucho
Mehvish Ali
94

por favor agregue esta línea al tema de su aplicación

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

para obtener más información: https://developer.android.com/topic/performance/vitals/launch-time#themed

Hitesh Singh
fuente
25
Cuelga la aplicación durante 2 segundos y luego se inicia, ¡no es útil para mí!
Faakhir
4
rallar ahora no muestra el color #ffffff pero ahora muestra # 000000
Midhilaj
@Faakhir Entonces, ¿encontraste alguna solución? Todavía estoy buscando una solución, que elimine esta pantalla blanca y que no haya demora en el momento del lanzamiento.
Rupam Das
33

Copie y pegue estas dos líneas en el tema de su aplicación de manifiesto, es decir, res / styles / AppTheme. entonces funcionará a las mil maravillas.

<item name="android:windowDisablePreview">true</item>
<item name="android:windowIsTranslucent">true</item>
prasad reddy
fuente
20

La forma recomendada de resolver este problema falta en las respuestas. Entonces estoy agregando mi respuesta aquí. El problema de la pantalla blanca al inicio se produce debido a la pantalla en blanco inicial que dibuja el proceso del sistema al iniciar la aplicación. Una forma común de resolver esto es apagando esta pantalla inicial agregando esto a su styles.xmlarchivo.

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

Pero de acuerdo con la documentación de Android, esto puede resultar en un tiempo de inicio más largo. La forma recomendada de evitar esta pantalla blanca inicial según Google es utilizar el windowBackgroundatributo de tema de la actividad y proporcionar un simple dibujable personalizado para la actividad inicial.

Me gusta esto:

Archivo de diseño dibujable, 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>

Crea un nuevo estilo en tu 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>

Agregue este tema a su actividad inicial en el archivo de manifiesto

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

Y cuando desee volver a su llamada temática normal setTheme(R.style.Apptheme)antes de llamar super.onCreate()ysetContentView()

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

Esta es la forma recomendada de resolver el problema y proviene de los patrones de Google Material Design .

Sam
fuente
14

¿Ha intentado establecer el android:windowBackgroundatributo en el tema de la actividad de su lanzador, ya sea en un color o en un dibujable?

Por ejemplo esto:

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

cuando se agrega al tema de actividad del Lanzador, se mostrará un color negro (en lugar del color blanco) al inicio. Este es un truco fácil para ocultar una inicialización larga, mientras muestra algo a los usuarios, y funciona bien incluso si subclasifica el objeto Aplicación.

Evite el uso de otras construcciones (incluso subprocesos) para realizar tareas de inicialización largas, ya que puede terminar no siendo capaz de controlar el ciclo de vida de dichas construcciones. El objeto Aplicación es el lugar correcto para realizar exactamente este tipo de acciones.

gmetal
fuente
14

Agregué las siguientes dos líneas en mi tema en styles.xml

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

Trabajado como un encanto

Akanshi Srivastava
fuente
10

Tuve el mismo problema, tienes que actualizar tu estilo.

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>

Su archivo de manifiesto debería verse a continuación.

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

Fuera fuera:

ingrese la descripción de la imagen aquí

Espero que esto te ayude.

Hiren Patel
fuente
2
Eso funciona muy bien para mí en una aplicación OpenGL de NativeActivity. No estoy seguro de por qué esto no está más arriba en las respuestas, ya que es la respuesta más completa y conveniente. Ningún Java implicó solo un par de cambios en el archivo XML.
Slion
7

Dentro de los métodos de devolución de llamada del ciclo de vida, puede declarar cómo se comporta su actividad cuando el usuario abandona y vuelve a ingresar a la actividad. Recuerde que la forma en que está diseñado Android, existe un ciclo de vida para todas y cada una de las aplicaciones. Si coloca demasiada carga en el onCreate()método (que es el método utilizado para cargar los archivos de diseño e inicializar los controles que tenga), la pantalla blanca se volverá más visible, ya que el archivo de diseño tardará más en cargarse.

Sugiero utilizar varios métodos diferentes al iniciar una actividad. Tales son onStart()(que se llama como lo primero una vez que se carga la aplicación), onActivityCreated()(se llama después de que se muestra el diseño y es útil si está realizando algún procesamiento de datos al iniciar la actividad).

Para que le resulte más fácil, a continuación se muestra el diagrama oficial del ciclo de vida de la actividad:

ingrese la descripción de la imagen aquí

Michele La Ferla
fuente
Gracias por tu respuesta, fue muy interesante. Sin embargo, creo que entendiste mal mi pregunta. El problema no es causado por las inicializaciones en la primera Activity, sino por las del Applicationobjeto global . Y no creo que pueda aplicar tal separación de preocupaciones allí, porque a diferencia de una Activity, solo tiene un onCreate()método.
YS
¿Por qué está ampliando la clase de aplicación y no la de actividad?
Michele La Ferla
Bien, entonces quieres decir que debería abandonar el Applicationobjeto por completo y mover todo el código de inicialización al primero Activity...
YS
Así es como siempre he desarrollado mis aplicaciones; sin embargo, si no desea realizar todos esos cambios, otras respuestas pueden ayudarlo a solucionar su problema utilizando la clase de aplicación. Para su referencia futura, recomiendo usar la clase de una actividad inmediatamente y luego muchos fragmentos. Espero que esto ayude :)
Michele La Ferla
2

¿Intentaste poner la inicialización onActivityCreated?

Dentro de la Applicationclase:

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

            }
        });
Sergey Shustikov
fuente
2

Como ya sabe por qué esta pantalla blanca está allí, debido a procesos en segundo plano o inicialización de aplicaciones o archivos grandes, simplemente verifique la idea a continuación para superar esto.

Para evitar esta pantalla en blanco al comienzo de la aplicación, una forma es la pantalla de inicio, esta es solo una forma no final y debe tener que usarla.

Cuando muestre la pantalla de bienvenida de su archivo splash.xml, este problema seguirá siendo el mismo,

Por lo tanto, debe crear un estilo ont en el archivo style.xml para la pantalla de presentación y allí debe establecer el fondo de la ventana como su imagen de presentación y luego aplicar ese tema a su actividad de presentación desde el archivo de manifiesto. Entonces, cuando ejecute la aplicación, primero establecerá el tema y, de esta manera, el usuario podrá ver directamente la imagen de bienvenida en lugar de la pantalla blanca.

Vickyexpert
fuente
2

Ambas propiedades funcionan

    <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>
Sohail Zahid
fuente
2

Intente esto una vez.

1) Cree un archivo dibujable 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) Pon esto en styles.xml

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

3) En su AndroidMainfest.xml, configure el tema anterior para Iniciar actividad.

       <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>
Surendar D
fuente
0

Simplemente escriba el elemento en values ​​/ styles.xml:

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

Por ejemplo, en 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>
Javier Reinoso
fuente
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>
Krishna
fuente
0

Para cualquiera que tenga esa pantalla blanca mientras depura, tenga en cuenta que si está depurando, tardará más en cargar. Si crea su APK de lanzamiento y lo instala en su teléfono, notará que se tarda mucho menos en cargar.

Por lo tanto, el tiempo de inicio con la versión de depuración no es igual al tiempo de inicio con la versión de lanzamiento.

Mointy
fuente