Android: impedisce lo schermo bianco all'avvio


110

Come tutti sappiamo, molte app Android visualizzano una schermata bianca molto brevemente prima che la loro prima Activityvenga messa a fuoco. Questo problema si osserva nei seguenti casi:

  • App Android che estendono la Applicationclasse globale e vi eseguono importanti inizializzazioni. L' Application oggetto viene sempre creato prima del primo Activity(un fatto che può essere osservato nel debugger), quindi ha senso. Questa è la causa del ritardo nel mio caso.

  • App Android che visualizzano la finestra di anteprima predefinita prima della schermata iniziale.

L'impostazione android:windowDisablePreview = "true"ovviamente non funziona qui. Né posso impostare il tema principale della schermata iniziale Theme.Holo.NoActionBarcome descritto qui , perché [sfortunatamente] la mia schermata iniziale utilizza un file ActionBar.

Nel frattempo, le app che non estendono la Applicationclasse non mostrano la schermata bianca all'avvio.

Il fatto è che idealmente le inizializzazioni eseguite Applicationnell'oggetto devono avvenire prima cheActivity venga mostrato il primo . Quindi la mia domanda è: come posso eseguire queste inizializzazioni all'avvio dell'app senza utilizzare un Applicationoggetto? Forse usando un Threado Service, suppongo?

Questo è un problema interessante su cui riflettere. Non posso aggirarlo nel solito modo (impostando il NoActionBartema), poiché tragicamente la mia schermata iniziale ha effettivamente una ActionBarcausa per alcuni motivi non correlati.

Nota:

Ho già fatto riferimento alle seguenti domande:

Riferimenti:


1
Hai trovato il problema da solo, stai facendo a molti init nel contesto dell'applicazione, bloccando il caricamento dell'attività, prova ad asincronizzarlo, lasciando che un'attività di caricamento si presenti fino alla fine di qualche thread.
AxelH

Questo potrebbe aiutare
Max

1
Idealmente, un'applicazione scaricherà l'elaborazione e non utilizzerebbe il thread principale per operazioni lunghe. Questa è una pratica ben accettata. Se le operazioni devono essere eseguite prima del caricamento dell'app, almeno non dovrebbe condividere un thread con l'interfaccia utente.
Beshoy Hanna

1
Potresti scoprire che questo è ancora un problema dopo aver spostato tutto il Applicationcodice di inizializzazione fuori dalla classe. Ciò è dovuto alle versioni più recenti del modo in cui Android "avvia a freddo" le app. Google ha effettivamente affrontato i tempi di lancio all'I / O di Google quest'anno e sarà risolto in N da quello che ricordo. Nel frattempo, dovresti guardare a ciò che Google chiama una "schermata di lancio con marchio". Ecco un esempio su come crearlo: antonioleiva.com/branded-launch-screen - niente più schermo bianco all'inizio ;-) E per favore non usare splashscreen - è fastidioso per l'utente.
Darwind

1
Per quanto riguarda il tema, il trucco non è impostare un tema NoActionBar, ma regolare il tema dell'attività iniziale in modo che uno schermo a tema vuoto assomigli a quello completamente inizializzato.
zapl

Risposte:


86

Il problema con lo sfondo bianco è causato dall'avvio a freddo di Android mentre l'app viene caricata in memoria e può essere evitato con questo:

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

disposizione

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

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

Aggiungi questo tema alla tua schermata iniziale nel 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>

che produrrà un effetto come questo

un gatto indaffarato

per maggiori dettagli e più soluzioni puoi controllare questo BlogPost


3
non ha aiutato ancora lo schermo bianco e l'animazione alla fine
Mehvish Ali

Questa è un'implementazione semplice. Potrebbero esserci altre parti del codice che causano il problema. Apri un'altra domanda e sarò lì per aiutarti :)
Ivan Milisavljevic

1
Ho risolto questo problema animando tra i temi e cambiando il tema senza disegnare ma solo il colore dello sfondo lo stesso e poi su WindowsFocusChanged () ha reso visibile il contenuto e lo ha animato diversamente dal mio bianco tra la transizione. l'animazione dei temi ha aiutato molto
Mehvish Ali

94

aggiungi questa riga nel tema della tua app

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

per maggiori informazioni: https://developer.android.com/topic/performance/vitals/launch-time#themed


25
Si blocca l'applicazione per 2 secondi e poi si avvia, non utile per me!
Faakhir

4
grate ora non mostra il colore #ffffff ma ora mostra # 000000
Midhilaj

@ Faakhir Quindi hai trovato qualche soluzione? Sto ancora cercando una soluzione, che rimuova questo schermo bianco e inoltre non ci siano ritardi al momento del lancio.
Rupam Das

33

Copia e incolla queste due righe nel tema dell'app manifest, ad esempio res / styles / AppTheme. allora funzionerà come un fascino ..

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


20

Il modo consigliato per risolvere questo problema manca nelle risposte. Quindi aggiungo la mia risposta qui. Il problema dello schermo bianco all'avvio si verifica a causa della schermata iniziale vuota che il processo di sistema disegna all'avvio dell'app. Un modo comune per risolvere questo problema è disattivare questa schermata iniziale aggiungendola al styles.xmlfile.

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

Ma secondo la documentazione di Android ciò può comportare tempi di avvio più lunghi. Il modo consigliato per evitare questa schermata bianca iniziale secondo Google è utilizzare l' windowBackgroundattributo del tema dell'attività e fornire un semplice disegno personalizzato per l'attività iniziale.

Come questo:

File di layout disegnabile, 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 nuovo stile nel tuo file 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>

Aggiungi questo tema alla tua attività iniziale nel file Manifest

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

E quando vuoi tornare alla normale chiamata a tema setTheme(R.style.Apptheme)prima di chiamare super.onCreate()esetContentView()

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

Questo è il modo consigliato per risolvere il problema e questo è da Google Material Design patterns.


14

Hai provato a impostare l' android:windowBackgroundattributo nel tema della tua attività di avvio, su un colore o su un disegnabile?

Ad esempio questo:

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

quando aggiunto al tema dell'attività di avvio, all'avvio verrà visualizzato un colore nero (anziché il colore bianco). Questo è un trucco facile per nascondere una lunga inizializzazione, mostrando qualcosa agli utenti, e funziona bene anche se si sottoclasse l'oggetto Application.

Evita di usare altri costrutti (anche Thread) per eseguire lunghe attività di inizializzazione, perché potresti finire per non essere in grado di controllare il ciclo di vita di tali costrutti. L'oggetto Application è il luogo corretto per eseguire esattamente questo tipo di azioni.


14

Ho aggiunto le seguenti due righe nel mio tema in styles.xml

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

Ha funzionato come un fascino


10

Ho avuto lo stesso problema, devi aggiornare il tuo stile.

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>

Il tuo file manifest dovrebbe apparire come di seguito.

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

Fuori fuori:

inserisci qui la descrizione dell'immagine

Spero che questo ti possa aiutare.


2
Per me funziona benissimo su un'applicazione OpenGL NativeActivity. Non sono sicuro del motivo per cui questo non è più in alto nelle risposte in quanto è la risposta più completa e conveniente. Nessun Java ha coinvolto solo un paio di modifiche ai file XML.
Slion

7

All'interno dei metodi di callback del ciclo di vita, puoi dichiarare come si comporta la tua attività quando l'utente esce e rientra nell'attività. Ricorda che il modo in cui Android è progettato, c'è un ciclo di vita per ogni app. Se si carica troppo il onCreate()metodo (che è il metodo utilizzato per caricare i file di layout e inizializzare i controlli in esso contenuti), lo schermo bianco diventerà più visibile, poiché il caricamento del file di layout richiederà più tempo.

Suggerisco di utilizzare diversi metodi quando si avvia un'attività. Tali sono onStart()(viene chiamato come prima cosa una volta caricata l'app), onActivityCreated()(viene chiamato dopo che il layout è stato visualizzato e utile se si sta effettuando l'elaborazione dei dati all'avvio dell'attività).

Per renderti più facile, di seguito è riportato il diagramma del ciclo di vita dell'attività ufficiale:

inserisci qui la descrizione dell'immagine


Grazie per la tua risposta, è stata molto interessante. Tuttavia, credo che tu abbia frainteso la mia domanda. Il problema non è causato dalle inizializzazioni nella prima Activity, ma da quelle Applicationnell'oggetto globale . E non credo di poter applicare una tale separazione di interessi lì, perché a differenza di un Activityha solo un onCreate()metodo.
YS

Perché estendi la classe dell'applicazione e non quella dell'attività?
Michele La Ferla

Ok, quindi vuoi dire che dovrei abbandonare del Applicationtutto l' oggetto e spostare tutto il codice di inizializzazione nel primo Activity...
YS

È così che ho sempre sviluppato le mie app, tuttavia se non desideri apportare tutte queste modifiche, altre risposte potrebbero aiutarti a risolvere il problema utilizzando la classe dell'applicazione. Come riferimento futuro, consiglio di utilizzare immediatamente una classe di attività e quindi molti frammenti. Spero che questo aiuti :)
Michele La Ferla

2

Hai provato a mettere l'inizializzazione su onActivityCreated?

All'interno della 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) {

            }
        });

2

Come già sapete perché questa schermata bianca è presente, a causa di processi in background o inizializzazione dell'applicazione o file di grandi dimensioni, quindi controllate sotto l'idea per ovviare a questo.

Per evitare questo schermo bianco all'inizio dell'app, un modo è lo splash screen, questo è solo un modo non definitivo e devi usare.

Quando mostrerai la schermata iniziale dal tuo file splash.xml, anche questo problema rimarrà lo stesso,

Quindi devi creare uno stile ont nel file style.xml per la schermata iniziale e lì devi impostare lo sfondo della finestra come immagine splash e quindi applicare quel tema alla tua attività splash dal file manifest. Quindi ora quando eseguirai l'app, per prima cosa imposterà il tema e in questo modo l'utente sarà in grado di vedere direttamente l'immagine splash invece dello schermo bianco.


2

Entrambe le proprietà funzionano

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

2

Per favore, prova una volta.

1) Crea un file disegnabile 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) Mettilo in styles.xml

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

3) Nel tuo AndroidMainfest.xml imposta il tema precedente su Avvia attività.

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

0

Basta scrivere l'elemento in values ​​/ styles.xml:

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

Ad esempio, in 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>

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>

0

Per chiunque abbia quello schermo bianco durante il debuging, tieni presente che se stai eseguendo il debuging, il caricamento richiederà più tempo. Se crei il tuo APK di rilascio e lo installi sul tuo telefono, noterai che ci vuole molto meno per caricarlo.

Quindi il tempo di avvio con la versione Debug non è uguale al tempo di avvio con la versione di rilascio.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.