Android - Empêcher l'écran blanc au démarrage

110

Comme nous le savons tous, de nombreuses applications Android affichent un écran blanc très brièvement avant leur première Activitymise au point. Ce problème est observé dans les cas suivants:

  • Applications Android qui étendent la Applicationclasse globale et y effectuent des initialisations majeures. L' Application objet est toujours créé avant le premier Activity(un fait qui peut être observé dans le débogueur), donc cela a du sens. C'est la cause du retard dans mon cas.

  • Applications Android qui affichent la fenêtre d'aperçu par défaut avant l'écran de démarrage.

Le réglage android:windowDisablePreview = "true"ne fonctionne évidemment pas ici. Je ne peux pas non plus définir le thème parent de l'écran de démarrage Theme.Holo.NoActionBarcomme décrit ici , car [malheureusement] mon écran de démarrage utilise un fichier ActionBar.

Pendant ce temps, les applications qui n'étendent pas la Applicationclasse n'affichent pas l'écran blanc au démarrage.

Le fait est que, idéalement, les initialisations effectuées dans l' Applicationobjet doivent se produire avant que la première ne Activitysoit affichée. Ma question est donc la suivante: comment puis-je effectuer ces initialisations au démarrage de l'application sans utiliser d' Applicationobjet? Peut-être en utilisant un Threadou Service, je suppose?

C'est un problème intéressant auquel réfléchir. Je ne peux pas le contourner de la manière habituelle (en définissant le NoActionBarthème), car tragiquement mon écran Splash a en fait une ActionBarraison pour des raisons indépendantes.

Remarque:

J'ai déjà évoqué les questions suivantes:

Références:

YS
la source
1
Vous avez trouvé le problème vous-même, vous faites beaucoup d'init dans le contexte de l'application, bloquez le chargement de l'activité, essayez de l'asynchroniser, laissant une activité de chargement apparaître jusqu'à la fin d'un thread.
AxelH
Cela pourrait aider
Max
1
Idéalement, une application déchargerait le traitement et n'utiliserait pas le thread principal pour de longues opérations. C'est une pratique bien acceptée. Si les opérations doivent avoir lieu avant le chargement de l'application, elle ne devrait au moins pas partager de thread avec l'interface utilisateur.
Beshoy Hanna
1
Vous constaterez peut-être que c'est toujours un problème après avoir déplacé tout le code d'initialisation hors de la Applicationclasse. Cela est dû aux nouvelles versions de la manière d'Android de "démarrer à froid" les applications. Google a en fait abordé les heures de lancement à Google I / O cette année et cela sera corrigé en N d'après ce dont je me souviens. En attendant, vous devriez regarder ce que Google appelle un "écran de lancement de marque". Voici un exemple sur la façon de le créer: antonioleiva.com/branded-launch-screen - plus d'écran blanc au début ;-) Et n'utilisez pas d'écrans de démarrage - c'est ennuyeux pour l'utilisateur.
Darwind
1
Thème Wrt, l'astuce n'est pas de définir un thème NoActionBar, c'est d'ajuster le thème de l'activité initiale afin qu'un écran thématique vide ressemble à celui entièrement initialisé.
zapl

Réponses:

86

Le problème avec le fond blanc est dû au démarrage à froid d'Android pendant le chargement de l'application en mémoire, et il peut être évité avec ceci:

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

disposition

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

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

Ajoutez ce thème à votre écran de démarrage dans le manifeste

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

qui produira un effet comme celui-ci

un chat occupé

pour plus de détails et plus de solutions, vous pouvez consulter ce BlogPost

Ivan Milisavljevic
la source
3
cela
n'a
Il s'agit d'une mise en œuvre simple. Il se peut que d'autres parties de votre code soient à l'origine du problème. Veuillez ouvrir une autre question et il sera là pour vous aider :)
Ivan Milisavljevic
1
J'ai résolu ce problème en animant entre les thèmes et en changeant le thème sans dessiner, mais juste la couleur arrière de la même manière, puis sur onWindowFocusChanged () rend le contenu visible et l'animé autrement ma blanchi entre la transition. l'animation des thèmes a beaucoup aidé
Mehvish Ali
94

veuillez ajouter cette ligne dans le thème de votre application

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

pour plus d'informations: https://developer.android.com/topic/performance/vitals/launch-time#themed

Hitesh Singh
la source
25
Il accroche l'application pendant 2 secondes puis le lancement de l'application, pas utile pour moi!
Faakhir
4
grille maintenant il
n'affiche
@Faakhir Alors avez-vous trouvé une solution? Je suis toujours à la recherche d'une solution, qui supprime cet écran blanc et il n'y a pas de retard au moment du lancement.
Rupam Das
33

Veuillez copier et coller ces deux lignes dans votre thème d'application manifeste, c'est-à-dire res / styles / AppTheme. alors ça fonctionnera comme du charme ..

<item name="android:windowDisablePreview">true</item>
<item name="android:windowIsTranslucent">true</item>
prasad reddy
la source
21

Tout d'abord, pour supprimer l'écran blanc, lisez ceci - https://www.bignerdranch.com/blog/splash-screens-the-right-way/

Mais plus important encore, optimisez votre charge initiale et reportez tout travail lourd au moment où vous avez le temps de l'exécuter. Publiez votre classe d'application ici si vous souhaitez que nous l'examinions.

Shmuel
la source
20

La méthode recommandée pour résoudre ce problème est absente des réponses. J'ajoute donc ma réponse ici. Le problème de l'écran blanc au démarrage se produit en raison de l'écran vide initial que le processus système dessine lors du lancement de l'application. Une façon courante de résoudre ce problème consiste à désactiver cet écran initial en l'ajoutant à votre styles.xmlfichier.

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

Mais selon la documentation Android, cela peut entraîner un temps de démarrage plus long. Selon Google, la méthode recommandée pour éviter cet écran blanc initial est d'utiliser l' windowBackgroundattribut de thème de l'activité et de fournir un dessin personnalisé simple pour l'activité de départ.

Comme ça:

Fichier de mise en page dessinable, 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>

Créez un nouveau style dans votre 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>

Ajoutez ce thème à votre activité de départ dans le fichier Manifest

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

Et lorsque vous souhaitez revenir à votre appel de thème normal setTheme(R.style.Apptheme)avant d'appeler super.onCreate()etsetContentView()

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

C'est la méthode recommandée pour résoudre le problème et cela provient des modèles de conception de matériaux de Google .

Sam
la source
14

Avez-vous essayé de définir l' android:windowBackgroundattribut dans le thème de votre activité de lancement, soit sur une couleur, soit sur un dessin?

Par exemple ceci:

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

lorsqu'il est ajouté au thème d'activité du lanceur, une couleur noire (plutôt que blanche) s'affiche au démarrage. C'est une astuce facile pour masquer une longue initialisation, tout en montrant quelque chose à vos utilisateurs, et cela fonctionne bien même si vous sous-classez l'objet Application.

Évitez d'utiliser d'autres constructions (même des threads) pour effectuer de longues tâches d'initialisation, car vous risquez de ne pas pouvoir contrôler le cycle de vie de telles constructions. L'objet Application est le bon endroit pour effectuer exactement ce type d'actions.

métal
la source
14

J'ai ajouté les deux lignes suivantes dans mon thème sous styles.xml

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

A travaillé comme un charme

Akanshi Srivastava
la source
10

J'ai eu le même problème, vous devez mettre à jour votre 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>

Votre fichier manifeste devrait ressembler à ci-dessous.

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

Dehors:

entrez la description de l'image ici

J'espère que cela vous aidera.

Hiren Patel
la source
2
Cela fonctionne très bien pour moi sur une application NativeActivity OpenGL. Je ne sais pas pourquoi ce n'est pas plus haut dans les réponses car c'est la réponse la plus complète et la plus rapide. Aucun Java n'impliquait seulement quelques modifications de fichiers XML.
Slion
7

Dans les méthodes de rappel du cycle de vie, vous pouvez déclarer le comportement de votre activité lorsque l'utilisateur quitte et réintègre l'activité. N'oubliez pas que la façon dont Android est conçu, il y a un cycle de vie pour chaque application. Si vous mettez trop de charge à la onCreate()méthode (qui est la méthode utilisée pour charger les fichiers de mise en page et initialiser tous les contrôles que vous y avez), l'écran blanc deviendra plus visible, car le fichier de mise en page prendra plus de temps à charger.

Je suggère d'utiliser plusieurs méthodes différentes lors du démarrage d'une activité. Tels sont les onStart()(étant appelé en premier lieu une fois l'application chargée), onActivityCreated()(étant appelé après l'affichage de la mise en page et utile si vous effectuez un traitement de données au démarrage de l'activité).

Pour vous faciliter la tâche, vous trouverez ci-dessous le diagramme officiel du cycle de vie des activités:

entrez la description de l'image ici

Michèle La Ferla
la source
Merci pour votre réponse, c'était très intéressant. Cependant, je pense que vous avez mal compris ma question. Le problème n'est pas causé par les initialisations de la première Activity, mais par celles de l' Applicationobjet global . Et je ne crois pas que je puisse appliquer une telle séparation des préoccupations là-bas, car contrairement à une, Activityelle n'a qu'une onCreate()méthode.
YS
Pourquoi étendez-vous la classe d'application et non l'activité?
Michele La Ferla
D'accord, vous voulez dire que je devrais abandonner Applicationcomplètement l' objet et déplacer tout le code d'initialisation vers le premier Activity...
YS
C'est ainsi que j'ai toujours développé mes applications, mais si vous ne souhaitez pas apporter toutes ces modifications, d'autres réponses peuvent vous aider à contourner votre problème en utilisant la classe d'application. Pour votre future référence, je recommande d'utiliser immédiatement une classe d'activité, puis de nombreux fragments. J'espère que cela aide :)
Michele La Ferla
2

Avez-vous essayé de mettre l'initialisation onActivityCreated?

À l'intérieur de la Applicationclasse:

 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
la source
2

Comme vous savez déjà pourquoi cet écran blanc est là, en raison des processus d'arrière-plan, de l'initialisation de l'application ou de fichiers volumineux, il suffit donc de vérifier ci-dessous l'idée pour surmonter cela.

Pour éviter cet écran blanc au début de l'application, un écran de démarrage est un moyen, ce n'est qu'un moyen non définitif et vous devez utiliser.

Lorsque vous afficherez l'écran de démarrage de votre fichier splash.xml, ce problème restera également le même,

Vous devez donc créer un style ont dans le fichier style.xml pour l'écran de démarrage et là, vous devez définir l'arrière-plan de la fenêtre comme image de démarrage, puis appliquer ce thème à votre activité de démarrage à partir du fichier manifeste. Alors maintenant, lorsque vous exécuterez l'application, elle définira d'abord le thème et, de cette manière, l'utilisateur pourra voir directement l'image de démarrage au lieu de l'écran blanc.

Vickyexpert
la source
2

Les deux propriétés fonctionnent

    <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
la source
2

Veuillez essayer ceci une fois.

1) Créez un fichier dessinable 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) Mettez ceci dans styles.xml

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

3) Dans votre AndroidMainfest.xml, définissez le thème ci-dessus sur Lancer l'activité.

       <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
la source
0

Écrivez simplement l'élément dans values ​​/ styles.xml:

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

Par exemple, dans l'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
la source
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
la source
0

Pour toute personne ayant cet écran blanc lors du débogage, sachez que si vous déboguez, le chargement prendra plus de temps. Si vous créez votre APK de version et l'installez sur votre téléphone, vous remarquerez que le chargement prend beaucoup moins de temps.

Ainsi, le temps de démarrage avec la version de débogage n'est pas égal au temps de démarrage avec la version commerciale.

Mointy
la source