Android - Weißer Bildschirm beim Start verhindern

110

Wie wir alle wissen, zeigen viele Android-Apps sehr kurz einen weißen Bildschirm an, bevor sie zum ersten Mal Activityin den Fokus rücken. Dieses Problem tritt in folgenden Fällen auf:

  • Android-Apps, die die globale ApplicationKlasse erweitern und wichtige Initialisierungen durchführen. Das Application Objekt wird immer vor dem ersten erstellt Activity(eine Tatsache, die im Debugger beobachtet werden kann), daher ist dies sinnvoll. Dies ist die Ursache für die Verzögerung in meinem Fall.

  • Android-Apps, die das Standardvorschaufenster vor dem Begrüßungsbildschirm anzeigen.

Die Einstellung android:windowDisablePreview = "true"funktioniert hier offensichtlich nicht. Ich kann das übergeordnete Thema des Begrüßungsbildschirms auch nicht Theme.Holo.NoActionBarwie hier beschrieben einstellen , da mein Begrüßungsbildschirm [leider] ein verwendet ActionBar.

Währenddessen wird bei Apps, die die ApplicationKlasse nicht erweitern , beim Start kein weißer Bildschirm angezeigt.

Die Sache ist, idealerweise müssen die im ApplicationObjekt durchgeführten Initialisierungen erfolgen, bevor die erste Activityangezeigt wird. Meine Frage ist also, wie ich diese Initialisierungen beim Start der App durchführen kann, ohne ein ApplicationObjekt zu verwenden. Möglicherweise mit einem Threadoder Service, nehme ich an?

Dies ist ein interessantes Problem. Ich kann es nicht auf die übliche Weise umgehen (indem ich das NoActionBarThema einstelle ), da mein Begrüßungsbildschirm tragischerweise aus ActionBarnicht verwandten Gründen tatsächlich einen hat .

Hinweis:

Ich habe bereits folgende Fragen angesprochen:

Verweise:

YS
quelle
1
Sie haben das Problem selbst gefunden. Sie führen zu vielen Init im Anwendungskontext durch, blockieren das Laden der Aktivität, versuchen, dies zu asynchronisieren, sodass eine Ladeaktivität angezeigt wird, bis ein Thread endet.
AxelH
Dies könnte helfen
Max
1
Im Idealfall würde eine Anwendung die Verarbeitung auslagern und den Hauptthread nicht für lange Vorgänge verwenden. Dies ist eine allgemein akzeptierte Praxis. Wenn die Vorgänge ausgeführt werden müssen, bevor die App geladen wird, sollte sie zumindest keinen Thread für die Benutzeroberfläche freigeben.
Beshoy Hanna
1
Möglicherweise ist dies immer noch ein Problem, nachdem Sie den gesamten Initialisierungscode aus der ApplicationKlasse entfernt haben. Dies ist auf neuere Versionen von Android zurückzuführen, mit denen die Apps "kalt gestartet" werden. Google hat sich dieses Jahr tatsächlich mit den Startzeiten bei Google I / O befasst und wird, soweit ich mich erinnere, in N festgelegt. In der Zwischenzeit sollten Sie sich ansehen, was Google als "Marken-Startbildschirm" bezeichnet. Hier ist ein Beispiel, wie man es erstellt: antonioleiva.com/branded-launch-screen - am Anfang kein weißer Bildschirm mehr ;-) Und bitte verwenden Sie keine Begrüßungsbildschirme - es ist für den Benutzer ärgerlich.
Darwind
1
Beim Thema besteht der Trick nicht darin, ein NoActionBar-Thema festzulegen, sondern das Thema der anfänglichen Aktivität so anzupassen, dass ein leerer Themenbildschirm wie der vollständig initialisierte aussieht.
Zapl

Antworten:

86

Das Problem mit dem weißen Hintergrund wird durch den Kaltstart von Android verursacht, während die App in den Speicher geladen wird, und kann folgendermaßen vermieden werden:

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

Layout

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

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

Fügen Sie dieses Thema Ihrem Begrüßungsbildschirm im Manifest hinzu

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

was zu einem solchen Effekt führen wird

eine beschäftigte Katze

Weitere Details und Lösungen finden Sie in diesem BlogPost

Ivan Milisavljevic
quelle
3
Es half nicht, immer noch weißen Bildschirm und Animation am Ende
Mehvish Ali
Dies ist eine einfache Implementierung. Möglicherweise gibt es einige andere Teile Ihres Codes, die das Problem verursachen. Bitte öffnen Sie eine andere Frage und ich
Ivan Milisavljevic
1
Ich habe dieses Problem gelöst, indem ich zwischen Themen animiert und das Thema geändert habe, ohne dass es gezeichnet werden konnte, sondern nur die gleiche Hintergrundfarbe. Dann hat onWindowFocusChanged () den sichtbaren Inhalt verrückt gemacht und ihn andernfalls auch zwischen den Übergängen animiert. Animation von Themen half viel
Mehvish Ali
91

Bitte fügen Sie diese Zeile in Ihr App-Thema ein

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

Weitere Informationen: https://developer.android.com/topic/performance/vitals/launch-time#themed

Hitesh Singh
quelle
24
Es hängt die Anwendung für 2 Sekunden und dann den Anwendungsstart, was für mich nicht nützlich ist!
Faakhir
4
Gitter jetzt zeigt es nicht #ffffff Farbe, aber es zeigt jetzt # 000000
Midhilaj
33

Bitte kopieren Sie diese beiden Zeilen und fügen Sie sie in Ihr Manifest-App-Thema ein, dh res / styles / AppTheme. dann wird es wie Charme funktionieren ..

<item name="android:windowDisablePreview">true</item>
<item name="android:windowIsTranslucent">true</item>
Prasad Reddy
quelle
21

Um den weißen Bildschirm zu entfernen, lesen Sie zunächst Folgendes: https://www.bignerdranch.com/blog/splash-screens-the-right-way/

Noch wichtiger ist jedoch, dass Sie Ihre anfängliche Last optimieren und jede schwere Arbeit auf den Zeitpunkt verschieben, an dem Sie Zeit haben, sie auszuführen. Veröffentlichen Sie Ihre Bewerbungsklasse hier, wenn Sie möchten, dass wir sie uns ansehen.

Shmuel
quelle
19

Die empfohlene Methode zur Lösung dieses Problems fehlt in den Antworten. Also füge ich hier meine Antwort hinzu. Das Problem mit dem weißen Bildschirm beim Start tritt aufgrund des anfänglichen leeren Bildschirms auf, den der Systemprozess beim Starten der App zeichnet. Ein üblicher Weg, dies zu lösen, besteht darin, diesen Startbildschirm auszuschalten, indem Sie ihn Ihrer styles.xmlDatei hinzufügen .

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

Laut Android-Dokumentation kann dies jedoch zu einer längeren Startzeit führen. Die empfohlene Möglichkeit, diesen anfänglichen weißen Bildschirm gemäß Google zu vermeiden, besteht darin, das windowBackgroundThemenattribut der Aktivität zu verwenden und eine einfache benutzerdefinierte Zeichnung für die Startaktivität bereitzustellen.

So was:

Zeichnungsfähige Layoutdatei, 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>

Erstellen Sie einen neuen Stil in Ihrem 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>

Fügen Sie dieses Thema zu Ihrer Startaktivität in der Manifest-Datei hinzu

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

Und wenn Sie zu Ihrem normalen Themenanruf zurückkehren möchten, setTheme(R.style.Apptheme)bevor Sie super.onCreate()und anrufensetContentView()

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

Dies ist der empfohlene Weg, um das Problem zu lösen. Dies basiert auf Google Material Design- Mustern.

Sam
quelle
14

Haben Sie versucht, das android:windowBackgroundAttribut im Thema Ihrer Launcher-Aktivität entweder auf eine Farbe oder auf eine Zeichenfunktion festzulegen?

Zum Beispiel dies:

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

Wenn es zum Launcher-Aktivitätsthema hinzugefügt wird, wird beim Start eine schwarze Farbe (anstelle der weißen Farbe) angezeigt. Dies ist ein einfacher Trick, um lange Initialisierungen zu verbergen und gleichzeitig Ihren Benutzern etwas anzuzeigen. Er funktioniert auch dann, wenn Sie das Anwendungsobjekt in Unterklassen unterteilen.

Vermeiden Sie die Verwendung anderer Konstrukte (auch Threads) für lange Initialisierungsaufgaben, da Sie möglicherweise den Lebenszyklus solcher Konstrukte nicht steuern können. Das Anwendungsobjekt ist der richtige Ort, um genau diese Art von Aktionen auszuführen.

Metall
quelle
14

Ich habe die folgenden zwei Zeilen in mein Thema unter styles.xml eingefügt

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

Lief wie am Schnürchen

Akanshi Srivastava
quelle
10

Ich hatte das gleiche Problem, Sie müssen Ihren Stil aktualisieren.

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>

Ihre Manifestdatei sollte wie folgt aussehen.

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

Raus:

Geben Sie hier die Bildbeschreibung ein

Hoffe das würde dir helfen.

Hiren Patel
quelle
2
Das funktioniert gut für mich in einer NativeActivity OpenGL-Anwendung. Ich bin mir nicht sicher, warum dies in den Antworten nicht weiter oben steht, da es die vollständigste und zweckmäßigste Antwort ist. Kein Java umfasste nur ein paar Änderungen an XML-Dateien.
Slion
7

Innerhalb der Lifecycle-Callback-Methoden können Sie festlegen, wie sich Ihre Aktivität verhält, wenn der Benutzer die Aktivität verlässt und erneut betritt. Denken Sie daran, dass bei der Gestaltung von Android für jede App ein Lebenszyklus vorhanden ist. Wenn Sie die onCreate()Methode zu stark laden (diese Methode wird zum Laden der Layoutdateien und zum Initialisieren aller darin enthaltenen Steuerelemente verwendet), wird der weiße Bildschirm besser sichtbar, da das Laden der Layoutdatei länger dauert.

Ich schlage vor, beim Starten einer Aktivität verschiedene Methoden anzuwenden. Dies sind die onStart()(werden als erstes aufgerufen, sobald die App geladen ist) onActivityCreated()(werden aufgerufen, nachdem das Layout angezeigt wurde, und nützlich, wenn Sie beim Starten der Aktivität eine Datenverarbeitung durchführen).

Um es Ihnen einfacher zu machen, finden Sie unten das offizielle Diagramm des Aktivitätslebenszyklus:

Geben Sie hier die Bildbeschreibung ein

Michele La Ferla
quelle
Vielen Dank für Ihre Antwort, es war sehr interessant. Ich glaube jedoch, dass Sie meine Frage falsch verstanden haben. Das Problem wird nicht durch die Initialisierungen im ersten Activity, sondern durch die im globalen ApplicationObjekt verursacht. Und ich glaube nicht, dass ich dort eine solche Trennung von Bedenken anwenden kann, weil es im Gegensatz zu einer Activitynur eine onCreate()Methode gibt.
YS
Warum erweitern Sie die Anwendungsklasse und nicht die Aktivitätsklasse?
Michele La Ferla
Okay, du meinst also, ich sollte das ApplicationObjekt ganz aufgeben und den gesamten Initialisierungscode auf den ersten verschieben Activity...
YS
So habe ich meine Apps immer entwickelt. Wenn Sie jedoch nicht alle diese Änderungen vornehmen möchten, können andere Antworten Ihnen helfen, Ihr Problem mithilfe der Anwendungsklasse zu umgehen. Als zukünftige Referenz empfehle ich, sofort eine Aktivitätsklasse und dann viele Fragmente zu verwenden. Hoffe das hilft :)
Michele La Ferla
2

Haben Sie versucht, die Initialisierung durchzuführen onActivityCreated?

Innerhalb der ApplicationKlasse:

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

Da Sie bereits wissen, warum dieser weiße Bildschirm aufgrund von Hintergrundprozessen oder Anwendungsinitialisierung oder großen Dateien vorhanden ist, überprüfen Sie einfach die folgende Idee, um diese zu überwinden.

Um diesen weißen Bildschirm zu Beginn der App zu verhindern, ist ein Weg der Begrüßungsbildschirm. Dies ist nur ein Weg, der nicht endgültig ist und den Sie verwenden müssen.

Wenn Sie den Begrüßungsbildschirm aus Ihrer Datei splash.xml anzeigen, bleibt auch dieses Problem gleich.

Sie müssen also einen ont-Stil in der Datei style.xml für den Begrüßungsbildschirm erstellen und dort den Fensterhintergrund als Begrüßungsbild festlegen und dieses Thema dann aus der Manifestdatei auf Ihre Begrüßungsaktivität anwenden. Wenn Sie nun die App ausführen, wird zuerst das Thema festgelegt, und auf diese Weise kann der Benutzer direkt das Begrüßungsbild anstelle des weißen Bildschirms sehen.

Vickyexpert
quelle
2

Beide Eigenschaften funktionieren

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

Bitte versuchen Sie dies einmal.

1) Erstellen Sie eine zeichnbare Datei 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) Fügen Sie dies in styles.xml ein

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

3) Stellen Sie in Ihrer AndroidMainfest.xml das obige Thema auf Aktivität starten ein.

       <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.
quelle
0

Schreiben Sie das Element einfach in values ​​/ styles.xml:

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

Zum Beispiel im 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
quelle
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
quelle
0

Wenn Sie diesen weißen Bildschirm während des Debuggens haben, beachten Sie, dass das Laden beim Debbug länger dauert. Wenn Sie die Release-APK erstellen und auf Ihrem Telefon installieren, werden Sie feststellen, dass das Laden viel weniger dauert.

Die Startzeit mit der Debbug-Version entspricht also nicht der Startzeit mit der Release-Version.

Mointy
quelle