App-Startzeit

Nutzer erwarten, dass Apps schnell geladen werden und reagieren. Eine App mit einer langen Startzeit entspricht nicht dieser Erwartung und kann Nutzer enttäuschen. Eine solche schlechte Nutzererfahrung kann dazu führen, dass Nutzer Ihre App im Play Store schlecht bewerten oder sie sogar gar nicht mehr verwenden.

Auf dieser Seite finden Sie Informationen zur Optimierung der Startzeit Ihrer App. Dazu gehören eine Übersicht über die Interna des Startvorgangs, Informationen zum Profiling der Startleistung und einige häufige Probleme mit der Startzeit sowie Tipps zur Behebung dieser Probleme.

Die verschiedenen App-Startzustände

Der App-Start kann in einem von drei Zuständen erfolgen: Kaltstart, Warmstart oder Heißstart. Jeder Status wirkt sich darauf aus, wie lange es dauert, bis Ihre App für den Nutzer sichtbar wird. Bei einem Kaltstart wird Ihre App von Grund auf neu gestartet. In den anderen Bundesstaaten muss das System die laufende App vom Hintergrund in den Vordergrund holen.

Wir empfehlen, immer von einem Kaltstart auszugehen. Dadurch kann auch die Leistung von Warm- und Heißstarts verbessert werden.

Um Ihre App für einen schnellen Start zu optimieren, ist es hilfreich zu verstehen, was auf System- und App-Ebene passiert und wie diese in den einzelnen Status interagieren.

Zwei wichtige Messwerte für den App-Start sind Zeit bis zur ersten Anzeige (Time to Initial Display, TTID) und Zeit bis zur vollständigen Anzeige (Time to Full Display, TTFD). TTID ist die Zeit, die benötigt wird, um den ersten Frame anzuzeigen, und TTFD ist die Zeit, die benötigt wird, bis die App vollständig interaktiv ist. Beide sind gleichermaßen wichtig, da der Nutzer anhand von TTID sieht, dass die App geladen wird, und TTFD angibt, wann die App tatsächlich nutzbar ist. Wenn einer dieser Schritte zu lange dauert, verlässt der Nutzer Ihre App möglicherweise, bevor sie überhaupt vollständig geladen ist.

Kaltstart

Ein Kaltstart bezieht sich auf den Start einer App von Grund auf. Das bedeutet, dass bis zu diesem Start der Prozess des Systems den Prozess der App erstellt. Kaltstarts treten beispielsweise auf, wenn Ihre App zum ersten Mal seit dem Start des Geräts oder seit dem Beenden der App durch das System gestartet wird.

Diese Art des Starts stellt die größte Herausforderung in Bezug auf die Minimierung der Startzeit dar, da das System und die App mehr leisten müssen als in den anderen Startzuständen.

Zu Beginn eines Kaltstarts hat das System die folgenden drei Aufgaben:

  1. Laden Sie die App und starten Sie sie.
  2. Nach dem Start der App wird sofort ein leeres Startfenster angezeigt.
  3. Erstellen Sie den Prozess für die App.

Sobald das System den App-Prozess erstellt hat, ist dieser für die nächsten Phasen verantwortlich:

  1. Erstellen Sie das App-Objekt.
  2. Starten Sie den Hauptthread.
  3. Erstellen Sie die Hauptaktivität.
  4. Initialisieren Sie die Benutzeroberfläche.
  5. Zeichne die Benutzeroberfläche auf dem Display.

Wenn der App-Prozess den ersten Draw abgeschlossen hat, tauscht der Systemprozess das angezeigte Hintergrundfenster aus und ersetzt es durch die Hauptaktivität. An diesem Punkt kann der Nutzer die App verwenden.

Weitere Informationen zu Layoutphasen in Compose finden Sie unter Jetpack Compose-Phasen.

Leistungsprobleme können bei der Erstellung der App und der Hostaktivität auftreten.

App-Erstellung

Wenn Ihre App gestartet wird, bleibt das leere Startfenster auf dem Bildschirm, bis das System die App zum ersten Mal gezeichnet hat. An diesem Punkt tauscht der Systemprozess das Startfenster für Ihre App aus, sodass der Nutzer mit der App interagieren kann.

Wenn Sie Application.onCreate in Ihrer eigenen App überschreiben, ruft das System die Methode onCreate für Ihr App-Objekt auf. Anschließend wird der Hauptthread, auch UI-Thread genannt, gestartet und mit der Erstellung der Hostaktivität der App beauftragt.

Ab diesem Punkt werden Prozesse auf System- und App-Ebene gemäß den Phasen des App-Lebenszyklus fortgesetzt.

Aktivitäten erstellen

Nachdem durch den App-Prozess Ihre Aktivität erstellt wurde, werden die folgenden Vorgänge ausgeführt:

  1. Initialisiert Werte.
  2. Ruft Konstruktoren auf.
  3. Ruft die Callback-Methode auf, z. B. Activity.onCreate, die dem aktuellen Lebenszyklusstatus der Aktivität entspricht.

In der Regel hat die onCreate-Methode die größten Auswirkungen auf die Ladezeit. In einer Jetpack Compose-App entsteht der Overhead der onCreate-Methode oft durch die erste Komposition. Das passiert, wenn Ihre App setContent aufruft und Ihre Composables auf oberster Ebene aufgerufen werden. Eine tiefe oder komplexe UI-Hierarchie oder Composables, die rechenintensive Berechnungen im Hauptthread ausführen, können diese Kompositionszeit verlängern.

Warm start

Ein Warmstart umfasst eine Teilmenge der Vorgänge, die bei einem Kaltstart stattfinden. Gleichzeitig ist der Aufwand höher als bei einem Heißstart. Es gibt viele potenzielle Status, die als Warmstarts betrachtet werden können, z. B. die folgenden:

  • Der Nutzer verlässt Ihre App, startet sie dann aber wieder. Der Prozess wird möglicherweise fortgesetzt, aber die App muss die Aktivität von Grund auf neu erstellen. Dazu muss sie onCreate aufrufen.

  • Das System entfernt Ihre App aus dem Arbeitsspeicher und der Nutzer startet sie dann neu. Der Prozess und die Aktivität müssen neu gestartet werden, aber die Aufgabe kann etwas von dem gespeicherten Instanzstatus-Bundle profitieren, das an onCreate übergeben wird.

Heißstart

Ein Heißstart Ihrer App hat einen geringeren Aufwand als ein Kaltstart. Bei einem Heißstart wird die Hostaktivität Ihrer App in den Vordergrund gebracht. Wenn die gesamte Benutzeroberfläche Ihrer App noch im Arbeitsspeicher vorhanden ist, kann die App die wiederholte Objektinitialisierung, UI-Initialisierung und das Rendering vermeiden.

Wenn jedoch aufgrund von Ereignissen zum Kürzen des Arbeitsspeichers, z. B. onTrimMemory, Arbeitsspeicher freigegeben wird, müssen diese Objekte als Reaktion auf das Heißstart-Ereignis neu erstellt werden.

Bei einem Heißstart wird auf dem Bildschirm dasselbe Verhalten wie bei einem Kaltstart angezeigt. Der Systemprozess zeigt einen leeren Bildschirm an, bis die App die Aktivität gerendert hat.

Abbildung 1. Ein Diagramm mit den verschiedenen Startzuständen und den entsprechenden Prozessen, wobei jeder Zustand mit dem ersten gezeichneten Frame beginnt.

App-Start in Perfetto identifizieren

Um Probleme beim Starten der App zu beheben, ist es hilfreich, genau zu wissen, was in der Startphase der App passiert. So identifizieren Sie die gesamte App-Startphase in Perfetto:

  1. Suchen Sie in Perfetto nach der Zeile mit dem abgeleiteten Messwert „Android App Startups“. Wenn Sie sie nicht sehen, versuchen Sie, einen Trace mit der App für die Systemanalyse auf dem Gerät aufzuzeichnen.

    Abbildung 2. Der abgeleitete Messwert-Slice „Android App Startups“ in Perfetto.
  2. Klicken Sie auf das zugehörige Segment und drücken Sie m, um es auszuwählen. Klammern um den Abschnitt geben an, wie lange er gedauert hat. Die Dauer wird auch auf dem Tab Aktuelle Auswahl angezeigt.

  3. Pinnen Sie die Zeile „Android App Startups“, indem Sie auf das Pinsymbol klicken, das angezeigt wird, wenn Sie den Mauszeiger auf die Zeile bewegen.

  4. Scrollen Sie zur Zeile mit der entsprechenden App und klicken Sie auf die erste Zelle, um die Zeile zu maximieren.

  5. Zoomen Sie in den Hauptthread, der sich normalerweise oben befindet, indem Sie w drücken. Mit s, a und d können Sie herauszoomen, nach links und nach rechts verschieben.

    Abbildung 3. Der abgeleitete Messwert „Android App Startups“ wird neben dem Hauptthread der App angezeigt.
  6. Der abgeleitete Messwert-Slice erleichtert es, genau zu sehen, was im App-Start enthalten ist, damit Sie weiterhin detaillierter debuggen können.

Wenn Sie eine Jetpack Compose-Anwendung analysieren, können Sie Composition Tracing verwenden, um detaillierte Informationen zur Leistung Ihrer Benutzeroberfläche zu erhalten. Achten Sie besonders auf Trace-Abschnitte im Hauptthread, die mit Choreographer#doFrame beginnen. Suchen Sie nach Segmenten wie Compose:recompose, Compose:layout und Compose:draw. Hier sehen Sie, wie viel Zeit Ihre App für das Erstellen, Messen, Platzieren und Zeichnen bestimmter Komponenten benötigt.

Messwerte zur Überprüfung und Verbesserung von Start-ups verwenden

Um die Leistung der Startzeit richtig zu analysieren, können Sie Messwerte erfassen, die zeigen, wie lange es dauert, bis Ihre App gestartet wird. Android bietet verschiedene Möglichkeiten, um Sie darauf hinzuweisen, dass Ihre App ein Problem hat, und Ihnen bei der Diagnose zu helfen.

Vorteile der Verwendung von Startup-Messwerten

Android verwendet die Messwerte Zeit bis zur ersten Anzeige (Time to Initial Display, TTID) und Zeit bis zur vollständigen Anzeige (Time to Full Display, TTFD), um Kalt- und Warmstarts von Apps zu optimieren. Die Android-Laufzeit (ART) verwendet die Daten aus diesen Messwerten, um Code effizient vorzukompilieren und so zukünftige Starts zu optimieren.

Schnellere Starts führen zu einer längeren Nutzerinteraktion mit Ihrer App. Dadurch wird die Wahrscheinlichkeit verringert, dass Nutzer die App frühzeitig beenden, die Instanz neu starten oder zu einer anderen App wechseln.

Zeit bis zur ersten Anzeige

Die Zeit bis zur ersten Anzeige (Time to Initial Display, TTID) ist die Zeit, die benötigt wird, um den ersten Frame der Benutzeroberfläche der App anzuzeigen. Mit diesem Messwert wird die Zeit gemessen, die eine App benötigt, um den ersten Frame zu rendern. Dazu gehören die Prozessinitialisierung bei einem Kaltstart, die Aktivitätserstellung bei einem Kalt- oder Warmstart und die Anzeige des ersten Frames. Wenn die TTID Ihrer App niedrig ist, wird die Nutzerfreundlichkeit verbessert, da Nutzer sehen, dass Ihre App schnell gestartet wird. Die TTID wird für jede App automatisch vom Android-Framework gemeldet. Wenn Sie die App-Startzeit optimieren möchten, empfehlen wir die Implementierung von reportFullyDrawn, um Informationen bis zum TTFD zu erhalten.

Die TTID wird als Zeitwert gemessen, der die gesamte verstrichene Zeit umfasst, die die folgende Ereignissequenz beinhaltet:

  • Den Prozess starten
  • Objekte initialisieren
  • Erstellen und Initialisieren der Hostaktivität
  • Benutzeroberfläche wird initialisiert.
  • Die App wird zum ersten Mal gezeichnet.

TTID abrufen

Suchen Sie im Logcat-Befehlszeilentool nach einer Ausgaberzeile mit dem Wert Displayed, um die TTID zu finden. Dieser Wert ist die TTID und sieht etwa so aus:

ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms

Wenn Sie die TTID in Android Studio finden möchten, deaktivieren Sie die Filter in der Logcat-Ansicht über das Drop-down-Filtermenü und suchen Sie dann nach der Displayed-Zeit (siehe Abbildung 4). Das Deaktivieren der Filter ist erforderlich, da dieser Log vom Systemserver und nicht von der App selbst bereitgestellt wird.

Abbildung 4: Deaktivierte Filter und der Wert Displayed in Logcat

Der Messwert Displayed in der Logcat-Ausgabe erfasst nicht unbedingt die Zeit, bis alle Ressourcen geladen und angezeigt werden. Ressourcen, auf die in der ursprünglichen Komposition nicht verwiesen wird (z. B. asynchron geladene Daten oder Bilder), oder Ressourcen, die die App im Rahmen der Objektinitialisierung erstellt, werden nicht berücksichtigt. Diese Ressourcen werden ausgeschlossen, da das Laden ein Inline-Prozess ist und die anfängliche Darstellung der App nicht blockiert. Weitere Informationen zu Ressourcen finden Sie unter Ressourcen in Compose.

Manchmal enthält die Zeile Displayed in der Logcat-Ausgabe ein zusätzliches Feld für die Gesamtzeit, wie im folgenden Beispiel:

ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms (total +1m22s643ms)

In diesem Fall erfolgt die erste Zeitmessung nur für die Aktivität, die zuerst gezeichnet wird, in der Regel die Host-Aktivität. Die Zeitmessung für total beginnt mit dem Start des App-Prozesses und kann eine andere Aktivität umfassen, die zuerst gestartet wird, aber nichts auf dem Bildschirm anzeigt. Die Zeitmessung total wird nur angezeigt, wenn es einen Unterschied zwischen den Startzeiten für die einzelne Aktivität und für den gesamten Start gibt.

Wir empfehlen, Logcat in Android Studio zu verwenden. Wenn Sie Android Studio nicht verwenden, können Sie die TTID auch messen, indem Sie Ihre App mit dem Shell-Befehl adb des Activity Managers ausführen. Beispiel:

adb [-d|-e|-s <serialNumber>] shell am start -S -W
com.example.app/.MainActivity
-c android.intent.category.LAUNCHER
-a android.intent.action.MAIN

Der Messwert Displayed wird wie bisher in der Logcat-Ausgabe angezeigt. In Ihrem Terminalfenster wird Folgendes angezeigt:

Starting: Intent
Activity: com.example.app/.MainActivity
ThisTime: 2044
TotalTime: 2044
WaitTime: 2054
Complete

Die Argumente -c und -a sind optional und ermöglichen es Ihnen, <category> und <action> anzugeben.

Zeit bis zur vollständigen Anzeige

Die Zeit bis zur vollständigen Anzeige (Time to Full Display, TTFD) ist die Zeit, die eine App benötigt, bis sie für den Nutzer interaktiv wird. Sie gibt an, wie lange es dauert, bis der erste Frame der Benutzeroberfläche der App und die Inhalte, die asynchron nach der Anzeige des ersten Frames geladen werden, angezeigt werden. In der Regel handelt es sich dabei um primäre Inhalte, die aus dem Netzwerk oder von der Festplatte geladen werden, wie von der App gemeldet. Mit anderen Worten: TTFD umfasst sowohl TTID als auch die Zeit, die benötigt wird, bis die App verwendet werden kann. Wenn die TTFD Ihrer App niedrig ist, können Nutzer schnell mit Ihrer App interagieren, was die Nutzerfreundlichkeit verbessert.

Das System kann die TTID zwar ermitteln, wenn das Hostfenster den ersten Frame rendert, aber die TTFD kann nicht automatisch ermittelt werden. Da Apps ihre primären Inhalte oft asynchron laden, weiß das System nicht, wann die App für den Nutzer tatsächlich vollständig nutzbar ist. Um TTFD zu ermitteln, muss die App dem System signalisieren, wenn sie den vollständig gerenderten Zustand erreicht.

TTFD abrufen

Um TTFD zu ermitteln, signalisieren Sie den vollständig gezeichneten Zustand, indem Sie die Methode reportFullyDrawn des ComponentActivity aufrufen. Die Methode reportFullyDrawn gibt an, wann die App vollständig gerendert wurde und sich in einem nutzbaren Zustand befindet. Die TTFD ist die Zeit, die vergeht, bis reportFullyDrawn aufgerufen wird, nachdem das System den Intent zum Starten der App empfangen hat. Wenn Sie reportFullyDrawn nicht aufrufen, wird kein TTFD-Wert gemeldet.

Rufen Sie reportFullyDrawn auf, nachdem Sie die Benutzeroberfläche und alle Daten vollständig gerendert haben, um die TTFD zu messen. Rufen Sie reportFullyDrawn nicht auf, bevor das Fenster der ersten Aktivität vom System gemessen und angezeigt wird, da das System sonst die vom System gemessene Zeit meldet. Wenn Sie reportFullyDrawn aufrufen, bevor das System die TTID erkennt, werden sowohl TTID als auch TTFD als derselbe Wert gemeldet. Dieser Wert ist der TTID-Wert.

Wenn Sie reportFullyDrawn verwenden, wird in Logcat eine Ausgabe wie im folgenden Beispiel angezeigt, in dem die TTFD 1 s 54 ms beträgt:

system_process I/ActivityManager: Fully drawn {package}/.MainActivity: +1s54ms

Die Logcat-Ausgabe enthält manchmal eine total-Zeit, wie im Abschnitt Zeit bis zur ersten Anzeige beschrieben.

Wenn die Anzeigedauer langsamer ist als gewünscht, können Sie versuchen, die Engpässe im Startvorgang zu ermitteln.

Mit reportFullyDrawn können Sie den vollständig gezeichneten Zustand in einfachen Fällen signalisieren, in denen Sie wissen, dass er erreicht wird. Wenn Hintergrundthreads jedoch Hintergrundaufgaben ausführen müssen, bevor der vollständig gerenderte Zustand erreicht wird, müssen Sie reportFullyDrawn verzögern, um eine genauere TTFD-Messung zu erhalten. Informationen dazu, wie Sie reportFullyDrawn verzögern, finden Sie im folgenden Abschnitt.

Genauigkeit der Startzeit verbessern

Wenn Ihre App Lazy Loading verwendet und die erste Anzeige nicht alle Ressourcen enthält, z. B. wenn Ihre App Bilder aus dem Netzwerk abruft, sollten Sie den Aufruf von reportFullyDrawn verzögern, bis Ihre App nutzbar ist. So können Sie die Listenerstellung in Ihre Benchmark-Zeitmessung einbeziehen.

Wenn die Benutzeroberfläche beispielsweise eine dynamische Liste wie LazyColumn oder LazyRow enthält, wird diese möglicherweise durch eine Hintergrundaufgabe gefüllt, die erst abgeschlossen wird, nachdem die Liste zum ersten Mal gerendert wurde und die Benutzeroberfläche daher als vollständig gerendert markiert ist. In solchen Fällen wird das Füllen der Liste nicht in das Benchmarking einbezogen.

Wenn Sie das Ausfüllen der Liste in Ihr Benchmark-Timing einbeziehen möchten, rufen Sie die FullyDrawnReporter mit fullyDrawnReporter ab und fügen Sie ihr in Ihrem App-Code einen Reporter hinzu. Geben Sie den Reporter frei, nachdem die Liste durch den Hintergrundtask gefüllt wurde.

FullyDrawnReporter ruft die Methode reportFullyDrawn erst auf, wenn alle hinzugefügten Reporter freigegeben wurden. Wenn Sie einen Reporter hinzufügen, ihn aber erst freigeben, wenn der Hintergrundprozess abgeschlossen ist, sind die Startzeitdaten auch die Zeit, die zum Erstellen der Liste benötigt wird. Das Verhalten der App für den Nutzer ändert sich dadurch nicht. reportFullyDrawn wird erst aufgerufen, wenn alle Aufgaben abgeschlossen sind, unabhängig von der Reihenfolge.

Wenn Ihre App Jetpack Compose verwendet, können Sie mit den folgenden APIs angeben, dass die App vollständig gerendert wurde:

  • ReportDrawn: Gibt an, dass Ihr Composable sofort für die Interaktion bereit ist.
  • ReportDrawnWhen: Akzeptiert ein Prädikat wie list.count > 0, um anzugeben, wann die Composable für die Interaktion bereit ist.
  • ReportDrawnAfter: Nimmt eine Methode zum Anhalten entgegen, die nach Abschluss angibt, dass das Composable für die Interaktion bereit ist.

Das folgende Beispiel zeigt, wie Sie mehrere Hintergrundaufgaben gleichzeitig ausführen können, wobei jede ihren eigenen Reporter registriert:

class MainActivity : ComponentActivity() {

    sealed interface ActivityState {
        data object LOADING : ActivityState
        data object LOADED : ActivityState
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            var activityState by remember {
                mutableStateOf(ActivityState.LOADING as ActivityState)
            }
            fullyDrawnReporter.addOnReportDrawnListener {
                activityState = ActivityState.LOADED
            }
            ReportFullyDrawnTheme {
                when(activityState) {
                    is ActivityState.LOADING -> {
                        // Display the loading UI.
                    }
                    is ActivityState.LOADED -> {
                        // Display the full UI.
                    }
                }
            }
            SideEffect {
                fullyDrawnReporter.addReporter()
                lifecycleScope.launch(Dispatchers.IO) {
                    // Perform the background operation.
                    fullyDrawnReporter.removeReporter()
                }
                fullyDrawnReporter.addReporter()
                lifecycleScope.launch(Dispatchers.IO) {
                    // Perform the background operation.
                    fullyDrawnReporter.removeReporter()
                }
            }
        }
    }
}
Engpässe identifizieren

Mit dem CPU Profiler von Android Studio können Sie nach Engpässen suchen. Weitere Informationen finden Sie unter CPU-Aktivität mit CPU Profiler untersuchen.

Außerdem können Sie durch Inline-Tracing in den onCreate-Methoden Ihrer Apps und Aktivitäten potenzielle Engpässe erkennen. Informationen zum Inline-Tracing finden Sie in der Dokumentation zu den Trace-Funktionen und in der Übersicht zum System-Tracing.

Häufige Probleme beheben

In diesem Abschnitt werden verschiedene Probleme behandelt, die sich häufig auf die Startleistung von Apps auswirken. Diese Probleme betreffen hauptsächlich die Initialisierung von App- und Aktivitätsobjekten sowie das Laden von Bildschirmen.

Aufwendige App-Initialisierung

Die Startleistung kann beeinträchtigt werden, wenn Ihr Code das Application-Objekt überschreibt und beim Initialisieren dieses Objekts umfangreiche oder komplexe Logik ausgeführt wird. Ihre App verschwendet möglicherweise Zeit beim Start, wenn Ihre Application-Unterklassen Initialisierungen ausführen, die noch nicht erforderlich sind.

Einige Initialisierungen sind möglicherweise völlig unnötig, z. B. wenn Statusinformationen für die Hauptaktivität initialisiert werden, wenn die App tatsächlich als Reaktion auf einen Intent gestartet wird. Bei einem Intent verwendet die App nur eine Teilmenge der zuvor initialisierten Statusdaten.

Weitere Herausforderungen bei der Initialisierung von Apps sind unter anderem automatische Speicherbereinigung-Ereignisse, die sich stark auswirken oder zahlreich sind, oder die gleichzeitige Ausführung von Laufwerk-E/A-Vorgängen während der Initialisierung, was den Initialisierungsprozess weiter blockiert. Die automatische Speicherbereinigung ist insbesondere bei der Dalvik-Laufzeit ein wichtiger Faktor. Die Android-Laufzeit (ART) führt die automatische Speicherbereinigung gleichzeitig aus, wodurch die Auswirkungen dieses Vorgangs minimiert werden.

Problem diagnostizieren

Sie können versuchen, das Problem mit der Methodenverfolgung oder der Inline-Verfolgung zu diagnostizieren.

Methoden-Tracing

Wenn Sie den CPU Profiler ausführen, sehen Sie, dass die Methode callApplicationOnCreate schließlich Ihre com.example.customApplication.onCreate-Methode aufruft. Wenn das Tool anzeigt, dass die Ausführung dieser Methoden lange dauert, sollten Sie genauer untersuchen, was dort passiert.

Inline-Tracing

Verwenden Sie das Inline-Tracing, um wahrscheinliche Ursachen zu untersuchen, z. B.:

  • Die ursprüngliche onCreate-Funktion Ihrer App.
  • Alle globalen Singleton-Objekte, die von Ihrer App initialisiert werden.
  • Alle Festplatten-E/A-Vorgänge, Deserialisierungen oder engen Schleifen, die während des Engpasses auftreten können.

Lösungen für das Problem

Unabhängig davon, ob das Problem mit unnötigen Initialisierungen oder mit der Festplatten-E/A zusammenhängt, ist die Lösung die verzögerte Initialisierung. Initialisieren Sie also nur Objekte, die sofort benötigt werden. Anstatt globale statische Objekte zu erstellen, sollten Sie ein Singleton-Muster verwenden, bei dem die App Objekte nur beim ersten Mal initialisiert, wenn sie sie benötigt.

Sie können auch ein Framework für die Abhängigkeitsinjektion wie Hilt verwenden, das Objekte und Abhängigkeiten erstellt, wenn sie zum ersten Mal eingefügt werden.

Wenn Ihre App Contentanbieter verwendet, um App-Komponenten beim Start zu initialisieren, sollten Sie stattdessen die App Startup-Bibliothek verwenden.

Initialisierung bei intensiver Aktivität

Das Erstellen von Aktivitäten ist oft mit viel Aufwand verbunden. Häufig gibt es Möglichkeiten, diese Arbeit zu optimieren, um die Leistung zu verbessern. Häufige Probleme sind:

  • Initialisieren einer großen oder komplexen Benutzeroberfläche
  • Umfangreiche Initialisierung in Composables
  • Das Zeichnen des Bildschirms auf der Festplatte oder die Netzwerk-E/A wird blockiert.
  • Bitmaps laden und decodieren.
  • VectorDrawable-Objekte werden gerastert.
  • Initialisierung anderer Subsysteme der Hostaktivität der App.

Problem diagnostizieren

Auch in diesem Fall können sowohl die Methoden- als auch die Inline-Ablaufverfolgung nützlich sein.

Methoden-Tracing

Achten Sie bei der Verwendung des CPU Profiler auf die Konstruktoren der Application-Unterklasse und die com.example.customApplication.onCreate-Methoden Ihrer App.

Wenn das Tool anzeigt, dass die Ausführung dieser Methoden lange dauert, sollten Sie genauer untersuchen, was dort passiert.

Inline-Tracing

Verwenden Sie das Inline-Tracing, um wahrscheinliche Ursachen zu untersuchen, darunter:

  • Die ursprüngliche onCreate-Funktion Ihrer App.
  • Alle globalen Singleton-Objekte, die initialisiert werden.
  • Alle Festplatten-E/A-Vorgänge, Deserialisierungen oder engen Schleifen, die während des Engpasses auftreten können.

Lösungen für das Problem

Es gibt viele potenzielle Engpässe, aber zwei häufige Probleme und Abhilfemaßnahmen sind:

  • Je größer die UI-Hierarchie, desto länger dauert es, bis die App sie initialisiert. Gehen Sie so vor, um das Problem zu beheben:
    • Flachen Sie die UI-Hierarchie ab, indem Sie redundante oder verschachtelte Composables reduzieren.
    • Vermeiden Sie unnötige Kompositionen und Neukompositionen beim Start.
    • Zusammensetzung der nicht kritischen Benutzeroberfläche verzögern
  • Wenn die gesamte Ressourceninitialisierung im Hauptthread erfolgt, kann sich auch der Start verlangsamen. So können Sie das Problem beheben:
    • Verschieben Sie die gesamte Ressourceninitialisierung, damit die App sie verzögert in einem anderen Thread ausführen kann.
    • Laden und rendern Sie die Benutzeroberfläche zuerst mit Platzhalterdaten und aktualisieren Sie dann visuelle Eigenschaften, die von Bitmaps und anderen Ressourcen abhängig sind.

Weitere Informationen zur Neukomposition finden Sie unter Neukomposition und Anzahl der Neukompositionen abrufen.

Benutzerdefinierte Ladebildschirme

Wenn Sie zuvor eine der folgenden Methoden verwendet haben, um unter Android 11 (API-Level 30) oder niedriger einen benutzerdefinierten Ladebildschirm zu implementieren, kann es beim Starten der App zu einer zusätzlichen Verzögerung kommen:

  • Mit dem Designattribut windowDisablePreview können Sie den anfänglichen leeren Bildschirm deaktivieren, der vom System beim Start gezeichnet wird.
  • Verwenden Sie eine spezielle Activity.

Ab Android 12 ist die Migration zur SplashScreen API erforderlich. Diese API ermöglicht eine schnellere Startzeit und bietet Ihnen die folgenden Möglichkeiten, den Splash-Screen anzupassen:

Außerdem wird die SplashScreen API durch die Compat-Bibliothek backportiert, um Abwärtskompatibilität zu ermöglichen und ein einheitliches Erscheinungsbild für die Anzeige von Splash-Screens auf allen Android-Versionen zu schaffen.

Weitere Informationen finden Sie im Migrationsleitfaden für den Splash-Screen.