App-Startzeit

Nutzer erwarten, dass Apps schnell geladen werden und schnell reagieren. Eine App mit einer langsamen Startzeit erfüllt diese Erwartungen nicht und kann Nutzer enttäuschen. Ein solches Problem kann dazu führen, dass Nutzer Ihre App im Play Store schlecht bewerten oder sogar ganz verlassen.

Diese Seite enthält Informationen zur Optimierung der Startzeit Ihrer Anwendung, einschließlich eines Überblicks über die internen Abläufe des Startprozesses, eines Profils für die Startleistung und einige häufige Probleme beim Start sowie Tipps zu deren Behebung.

Verschiedene App-Startstatus

Der App-Start kann in einem von drei Zuständen stattfinden: Kaltstart, Warmstart oder Heißstart. Jeder Status beeinflusst, wie lange es dauert, bis die Anwendung für den Nutzer sichtbar wird. Bei einem Kaltstart beginnt Ihre App bei null. In den anderen Status muss das System die laufende App aus dem Hintergrund in den Vordergrund bringen.

Wir empfehlen, für die Optimierung immer von einem Kaltstart auszugehen. Das kann auch die Leistung von Warm- und Heißstarts verbessern.

Um Ihre App für einen schnellen Start zu optimieren, ist es hilfreich zu verstehen, was auf System- und Anwendungsebene passiert und wie sie in jedem dieser Status interagieren.

Zwei wichtige Messwerte für die Bestimmung des Anwendungsstarts sind Zeit bis zur ersten Anzeige (Time to Initial Display, TTID) und Zeit bis zur vollständigen Anzeige (Time to Finish, TTFD). TTID ist die Zeit, die zum Anzeigen des ersten Frames benötigt wird, und TTFD die Zeit, die benötigt wird, bis die App vollständig interaktiv wird. Beide sind gleichermaßen wichtig, da TTID den Nutzer darüber informiert, dass die Anwendung geladen wird, und TTFD, wenn die Anwendung tatsächlich verwendet werden kann. Wenn einer dieser Werte zu lang ist, beendet der Nutzer die App möglicherweise, bevor sie vollständig geladen wurde.

Kaltstart

Ein Kaltstart bezieht sich darauf, dass eine App bei null beginnt. Dies bedeutet, dass der Prozess der Anwendung bis dahin vom Systemprozess erstellt wird. Kaltstarts treten beispielsweise auf, wenn Ihre App zum ersten Mal seit dem Start des Geräts gestartet oder nachdem das System die App beendet hat.

Diese Art von Start stellt die größte Herausforderung zur Minimierung der Startzeit dar, da das System und die App mehr Arbeit zu tun haben als in anderen Startstatus.

Zu Beginn eines Kaltstarts führt das System die drei folgenden Aufgaben aus:

  1. Laden Sie die App und starten Sie sie.
  2. Blenden Sie direkt nach dem Start ein leeres Startfenster für die App ein.
  3. Erstellen Sie den Anwendungsprozess.

Sobald das System den Anwendungsprozess erstellt hat, ist er für die nächsten Phasen verantwortlich:

  1. Erstellen Sie das Anwendungsobjekt.
  2. Starten Sie den Hauptthread.
  3. Erstellen Sie die Hauptaktivität.
  4. Steigern Sie die Anzahl der Aufrufe.
  5. Layout des Bildschirms.
  6. Führen Sie das erste Zeichnen aus.

Wenn der Anwendungsprozess die erste Zeichnung abgeschlossen hat, ersetzt der Systemprozess das angezeigte Hintergrundfenster durch die Hauptaktivität. Nun können Nutzende die App verwenden.

Abbildung 1 zeigt, wie die System- und Anwendungsprozesse Arbeit zwischeneinander übergeben.

Abbildung 1: Eine visuelle Darstellung der wichtigsten Teile einer kalten App-Einführung.

Leistungsprobleme können beim Erstellen der App und beim Erstellen der Aktivitä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 dieser Stelle vertauscht der Systemprozess das Startfenster für die Anwendung, sodass der Nutzer mit der Anwendung interagieren kann.

Wenn Sie Application.onCreate() in Ihrer eigenen App überschreiben, ruft das System die Methode onCreate() in Ihrem App-Objekt auf. Danach erstellt die Anwendung den Hauptthread, auch UI-Thread genannt, und weist ihn mit der Erstellung der Hauptaktivität zu.

Ab diesem Punkt werden die Prozesse auf System- und App-Ebene entsprechend den Lebenszyklusphasen der Anwendung fortgesetzt.

Aktivitäten erstellen

Nachdem der Anwendungsprozess Ihre Aktivität erstellt hat, führt die Aktivität die folgenden Vorgänge aus:

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

In der Regel hat die Methode onCreate() den größten Einfluss auf die Ladezeit, da sie die Arbeit mit dem höchsten Aufwand ausführt: das Laden und Aufblähen von Ansichten sowie das Initialisieren der Objekte, die zum Ausführen der Aktivität erforderlich sind.

Warm start

Ein Warmstart umfasst eine Teilmenge der Vorgänge, die während eines Kaltstarts stattfinden. Gleichzeitig ist dies mehr Aufwand als ein Heißstart. Es gibt viele potenzielle Zustände, die als Warmstarts betrachtet werden können, z. B. die folgenden:

  • Der Nutzer verlässt Ihre App, startet sie dann aber neu. Der Prozess wird möglicherweise weiter ausgeführt, aber die Anwendung muss die Aktivität mit einem Aufruf von onCreate() von Grund auf neu erstellen.

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

Heißstart

Ein Heißstart deiner App verursacht weniger Aufwand als ein Kaltstart. Bei einem Heißstart bringt das System deine Aktivität in den Vordergrund. Wenn sich alle Aktivitäten der Anwendung noch im Speicher befinden, kann die App eine wiederholte Objektinitialisierung, Layoutinflation und Wiederholung des Renderings vermeiden.

Wenn jedoch ein Teil des Arbeitsspeichers als Reaktion auf das Trimmen des Arbeitsspeichers (z. B. onTrimMemory()) dauerhaft gelöscht wird, müssen diese Objekte als Reaktion auf das Heißstartereignis neu erstellt werden.

Bei einem Heißstart ist auf dem Bildschirm das gleiche Verhalten zu sehen wie bei einem Kaltstart. Im Systemprozess wird ein leerer Bildschirm angezeigt, bis die App das Rendern der Aktivität abgeschlossen hat.

Abbildung 2: Ein Diagramm mit den verschiedenen Startstatus und ihren jeweiligen Prozessen, wobei jeder Zustand vom ersten gezeichneten Frame ausgeht.

App-Start-up in Perfetto erkennen

Zum Beheben von App-Startproblemen ist es hilfreich zu ermitteln, was genau in der App-Startphase enthalten ist. So ermitteln Sie die gesamte Startphase der App in Perfetto:

  1. Suchen Sie in Perfetto die Zeile mit dem abgeleiteten Messwert „Android-App-Starts“. Wenn Sie sie nicht sehen, versuchen Sie, einen Trace mit der On-Device-App für das System-Tracing zu erfassen.

    Abbildung 3: Abgeleitetes Messwertsegment „Android-App-Starts“ in Perfetto
  2. Klicken Sie auf das zugehörige Segment und drücken Sie m, um es auszuwählen. Um das Kreissegment herum werden Klammern angezeigt, die angeben, wie lange es gedauert hat. Die Dauer wird auch auf dem Tab Aktuelle Auswahl angezeigt.

  3. Sie können die Zeile „Android-App-Starts“ anpinnen, indem Sie auf das Stecknadelsymbol klicken. Es wird angezeigt, wenn Sie den Mauszeiger auf die Zeile bewegen.

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

  5. Zoomen Sie den Hauptthread, in der Regel oben, durch Drücken von w heran. Drücken Sie s, a, d, um herauszuzoomen, nach links bzw. nach rechts zu verschieben.

    Abbildung 4: Abgeleitetes Messwertsegment „Android-App-Starts“ neben dem Hauptthread der App
  6. Anhand des Slice der abgeleiteten Messwerte lässt sich leichter erkennen, was genau im App-Start enthalten ist, sodass Sie die Fehlerbehebung detaillierter durchführen können.

Start-ups mithilfe von Metriken untersuchen und verbessern

Um die Leistung während der Startzeit ordnungsgemäß zu diagnostizieren, können Sie Messwerte verfolgen, die zeigen, wie lange es dauert, bis Ihre Anwendung gestartet wird. Android bietet verschiedene Möglichkeiten, dir zu zeigen, dass bei deiner App ein Problem vorliegt, und es bei der Diagnose zu unterstützen. Android Vitals kann dir Benachrichtigungen senden, wenn ein Problem auftritt, und Diagnosetools können dir bei der Diagnose des Problems helfen.

Vorteile von Start-up-Messwerten

Android verwendet die Messwerte Time to Initial Display (TTID) und Time to Full Display (TTFD), um Kalt- und Warmstarts von Apps zu optimieren. Android Runtime (ART) verwendet die Daten aus diesen Messwerten, um Code zur Optimierung zukünftiger Start-ups effizient vorzukompilieren.

Schnellere Starts führen zu einer längeren Nutzerinteraktion mit Ihrer App, wodurch weniger Instanzen vorzeitig beendet, neu gestartet oder zu einer anderen App gewechselt werden.

Android Vitals

Android Vitals kann dir dabei helfen, die Leistung deiner App zu verbessern. Du wirst über die Play Console benachrichtigt, wenn die Startzeiten deiner App zu lange dauern.

Bei Android Vitals gelten die folgenden Startzeiten für deine App als übermäßig:

  • Der Kaltstart dauert 5 Sekunden oder länger.
  • Der Warmstart dauert 2 Sekunden oder länger.
  • Der Heißstart dauert 1,5 Sekunden oder länger.

In Android Vitals wird der Messwert Zeit bis zur ersten Anzeige (TTID) verwendet. Informationen dazu, wie Google Play Android Vitals-Daten erhebt, findest du in der Play Console-Dokumentation.

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 App-UI anzuzeigen. Dieser Messwert misst die Zeit, die eine App benötigt, um ihren ersten Frame zu erstellen. Dazu gehören die Prozessinitialisierung während eines Kaltstarts, die Aktivitätserstellung während eines Kalt- oder Warmstarts und die Anzeige des ersten Frames. Eine niedrige TTID für Ihre App trägt zu einer besseren Nutzererfahrung bei, da die Nutzer den Start Ihrer App schnell sehen können. Die TTID wird vom Android Framework automatisch für jede App gemeldet. Bei der Optimierung für App-Start-ups empfehlen wir, reportFullyDrawn zu implementieren, um Informationen bis TTFD zu erhalten.

Die TTID wird als Zeitwert gemessen, der die insgesamt verstrichene Zeit darstellt, die die folgende Ereignisabfolge umfasst:

  • Prozess starten
  • Objekte werden initialisiert.
  • Aktivität erstellen und initialisieren
  • Layout erweitern
  • Zeichnen der App zum ersten Mal

TTID abrufen

Zum Ermitteln der TTID suchen Sie im Logcat-Befehlszeilentool nach einer Ausgabezeile, die einen Wert namens Displayed enthält. Dieser Wert ist die TTID und entspricht in etwa dem folgenden Beispiel, in dem die TTID 3s534ms beträgt:

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

Um die TTID in Android Studio zu finden, deaktivieren Sie die Filter in der Logcat-Ansicht im Drop-down-Menü „Filter“ und suchen Sie nach der Displayed-Zeit (siehe Abbildung 5). Das Deaktivieren der Filter ist erforderlich, da der Systemserver und nicht die Anwendung selbst dieses Log bereitstellt.

Abbildung 5: 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 Layoutdatei nicht verwiesen wird oder die von der App im Rahmen der Objektinitialisierung erstellt werden, werden ausgelassen. Diese Ressourcen werden ausgeschlossen, da das Laden ein Inline-Prozess ist und die anfängliche Anzeige der Anwendung nicht blockiert wird.

Manchmal enthält die Zeile Displayed in der Logcat-Ausgabe ein zusätzliches Feld für die Gesamtzeit. Beispiele:

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

In diesem Fall gilt die erste Messung nur für die Aktivität, die zuerst erfasst wurde. Die Zeitmessung für total beginnt mit dem Start des Anwendungsprozesses 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 der einzelnen Aktivität und der Gesamtstartzeit gibt.

Wir empfehlen die Verwendung von Logcat in Android Studio. Wenn Sie Android Studio nicht nutzen, können Sie die TTID auch messen, indem Sie Ihre App mit dem Befehl adb im Shell-Aktivitätsmanager 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 in der Logcat-Ausgabe wie zuvor angezeigt. Im 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 die Angabe von <category> und <action>.

Zeit bis zur vollständigen Anzeige

Die Zeit bis zur vollständigen Anzeige (Time to Full Display, TTFD) ist die Zeit, die eine Anwendung benötigt, um für den Nutzer interaktiv zu werden. Sie wird als Zeit angegeben, die benötigt wird, um den ersten Frame der App-UI sowie den Inhalt anzuzeigen, der asynchron geladen wird, nachdem der erste Frame angezeigt wurde. In der Regel sind dies die primären Inhalte, die aus dem Netzwerk oder Laufwerk geladen und von der Anwendung gemeldet werden. Mit anderen Worten, TTFD enthält TTID sowie die Zeit, die für die Nutzung der Anwendung benötigt wird. Wenn Sie die TTFD-Datei Ihrer Anwendung niedrig halten, wird die Nutzerfreundlichkeit verbessert, da Nutzer schnell mit Ihrer Anwendung interagieren können.

Das System bestimmt die TTID, wenn Choreographer die Methode onDraw() der Aktivität aufruft und wenn bekannt, dass sie sie zum ersten Mal aufruft. Das System weiß jedoch nicht, wann TTFD bestimmt werden soll, da sich jede Anwendung anders verhält. Zum Ermitteln von TTFD muss die App dem System ein Signal senden, wenn sie den vollständig gezeichneten Zustand erreicht hat.

TTFD abrufen

Um TTFD zu ermitteln, signalisieren Sie den vollständig gezeichneten Zustand, indem Sie die Methode reportFullyDrawn() von ComponentActivity aufrufen. Die Methode reportFullyDrawn gibt an, wann die App vollständig gezeichnet und nutzbar ist. TTFD ist die Zeit, die zwischen dem Empfang des App-Start-Intents im System und dem Aufruf von reportFullyDrawn() verstrichen ist. Wenn Sie reportFullyDrawn() nicht aufrufen, wird kein TTFD-Wert gemeldet.

Rufen Sie zum Messen von TTFD reportFullyDrawn() auf, nachdem Sie die UI und alle Daten vollständig gezeichnet haben. Rufen Sie reportFullyDrawn() nicht auf, bevor das Fenster der ersten Aktivität zum ersten Mal gezeichnet und wie vom System gemessen angezeigt wird, da das System dann die gemessene Zeit meldet. Wenn Sie also reportFullyDrawn() aufrufen, bevor die TTID erkannt wird, meldet das System sowohl TTID als auch TTFD als denselben Wert. Dieser Wert ist dann der TTID-Wert.

Wenn Sie reportFullyDrawn() verwenden, zeigt Logcat eine Ausgabe wie das folgende Beispiel an, in der die TTFD-Datei 1s54ms beträgt:

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

Die Logcat-Ausgabe enthält manchmal einen total-Zeitpunkt, wie unter Zeit bis zur ersten Anzeige beschrieben.

Wenn die Anzeigezeiten langsamer als gewünscht sind, können Sie versuchen, die Engpässe beim Startvorgang zu identifizieren.

In grundlegenden Fällen, in denen Sie wissen, dass der vollständig gezeichnete Zustand erreicht ist, können Sie reportFullyDrawn() verwenden. In Fällen, in denen Hintergrundthreads jedoch Hintergrundarbeiten abschließen müssen, bevor der fertige Zustand erreicht ist, müssen Sie reportFullyDrawn() verzögern, um eine genauere TTFD-Messung zu erhalten. Informationen zum Verzögern von reportFullyDrawn() finden Sie im folgenden Abschnitt.

Präzision beim Startzeitpunkt verbessern

Wenn Ihre App Lazy Loading ausführt und die anfängliche 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, damit Sie die Listenpopulation in die Benchmark-Zeit integrieren können.

Wenn die UI beispielsweise eine dynamische Liste wie RecyclerView oder Lazy List enthält, kann sie durch eine Hintergrundaufgabe gefüllt werden, die abgeschlossen wird, nachdem die Liste zum ersten Mal gezeichnet wurde und somit als vollständig gezeichnet markiert wurde. In diesen Fällen wird die Bevölkerungszahl der Liste nicht im Benchmarking berücksichtigt.

Wenn Sie die Bevölkerung der Liste in das Benchmark-Timing einbeziehen möchten, rufen Sie den FullyDrawnReporter mithilfe von getFullyDrawnReporter() ab und fügen Sie ihm einen Reporter in Ihren App-Code hinzu. Sobald die Hintergrundaufgabe das Ausfüllen der Liste beendet hat, geben Sie den Reporter wieder frei.

FullyDrawnReporter ruft die Methode reportFullyDrawn() erst auf, wenn alle hinzugefügten Melder freigegeben wurden. Indem ein Reporter hinzugefügt wird, bis der Hintergrundprozess abgeschlossen ist, wird in den Zeitangaben auch die Zeit berücksichtigt, die zum Ausfüllen der Liste in den Startzeitdaten benötigt wird. Das Verhalten der Anwendung für den Nutzer ändert sich dadurch nicht. Die Daten zum Zeitpunkt des Startvorgangs enthalten jedoch die Zeit, die zum Ausfüllen der Liste benötigt wird. reportFullyDrawn() wird erst aufgerufen, wenn alle Aufgaben abgeschlossen sind, unabhängig von der Reihenfolge.

Das folgende Beispiel zeigt, wie Sie mehrere Hintergrundaufgaben gleichzeitig ausführen und jede einen eigenen Reporter registrieren:

Kotlin

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 {
                lifecycleScope.launch(Dispatchers.IO) {
                    fullyDrawnReporter.addReporter()

                    // Perform the background operation.

                    fullyDrawnReporter.removeReporter()
                }
                lifecycleScope.launch(Dispatchers.IO) {
                    fullyDrawnReporter.addReporter()

                    // Perform the background operation.

                    fullyDrawnReporter.removeReporter()
                }
            }
        }
    }
}

Java

public class MainActivity extends ComponentActivity {
    private FullyDrawnReporter fullyDrawnReporter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        fullyDrawnReporter = getFullyDrawnReporter();
        fullyDrawnReporter.addOnReportDrawnListener(() -> {
            // Trigger the UI update.
            return Unit.INSTANCE;
        });

        new Thread(new Runnable() {
            @Override
            public void run() {
                fullyDrawnReporter.addReporter();

                // Do the background work.

               fullyDrawnReporter.removeReporter();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                fullyDrawnReporter.addReporter();

                // Do the background work.

                fullyDrawnReporter.removeReporter();
            }
        }).start();
    }
}

Wenn Ihre Anwendung Jetpack Compose verwendet, können Sie die folgenden APIs verwenden, um den vollständig gezeichneten Zustand anzugeben:

  • ReportDrawn: Gibt an, dass die zusammensetzbare Funktion sofort für die Interaktion bereit ist.
  • ReportDrawnWhen: verwendet ein Prädikat wie list.count > 0, um anzugeben, wann die zusammensetzbare Funktion zur Interaktion bereit ist.
  • ReportDrawnAfter: verwendet eine Sperrmethode, die nach Abschluss anzeigt, dass die zusammensetzbare Funktion zur Interaktion bereit ist.
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 prüfen.

Durch Inline-Tracing in den onCreate()-Methoden Ihrer Anwendungen und Aktivitäten erhalten Sie auch Einblick in potenzielle Engpässe. Informationen zum Inline-Tracing finden Sie in der Dokumentation zu den Trace-Funktionen und in der Übersicht über System-Tracing.

Häufige Probleme beheben

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

Umfangreiche App-Initialisierung

Die Startleistung kann beeinträchtigt werden, wenn Ihr Code das Application-Objekt überschreibt und beim Initialisieren dieses Objekts aufwendige Arbeit oder komplexe Logik ausführt. Ihre Anwendung verschwendet möglicherweise Zeit beim Start, wenn Ihre abgeleiteten Application-Klassen Initialisierungen ausführen, die noch nicht ausgeführt werden müssen.

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

Weitere Herausforderungen bei der App-Initialisierung sind die automatische Speicherbereinigung, die besonders wirksam oder zahlreich sind, oder die Laufwerk-E/A, die gleichzeitig mit der Initialisierung stattfindet, wodurch der Initialisierungsprozess weiter blockiert wird. Die automatische Speicherbereinigung spielt insbesondere bei der Dalvik-Laufzeit eine Rolle. Die Android-Laufzeit (ART) führt gleichzeitig eine automatische Speicherbereinigung durch und minimiert so die Auswirkungen des Vorgangs.

Problem diagnostizieren

Sie können Methoden- oder Inline-Tracing verwenden, um das Problem zu diagnostizieren.

Methoden-Tracing

Wenn Sie den CPU-Profiler ausführen, sehen Sie, dass die Methode callApplicationOnCreate() schließlich Ihre Methode com.example.customApplication.onCreate aufruft. Wenn das Tool anzeigt, dass die Ausführung dieser Methoden lange dauert, untersuchen Sie weiter, welche Arbeit dort erfolgt.

Inline-Tracing

Verwenden Sie Inline-Tracing, um mögliche Ursachen zu untersuchen, z. B.:

  • Anfängliche onCreate()-Funktion Ihrer App.
  • Alle globalen Singleton-Objekte, die Ihre App initialisiert.
  • Jede Laufwerk-E/A, Deserialisierung oder enge Schleifen, die während des Engpasses auftreten können.

Lösungen für das Problem

Unabhängig davon, ob das Problem durch unnötige Initialisierungen oder die Laufwerks-E/A verursacht wird, ist die Lösung „verzögerte Initialisierung“. Mit anderen Worten: Initialisieren Sie nur Objekte, die sofort benötigt werden. Statt globale statische Objekte zu erstellen, sollten Sie zu einem Singleton-Muster wechseln, bei dem die Anwendung Objekte nur dann initialisiert, wenn sie sie zum ersten Mal benötigt.

Sie können auch ein Abhängigkeitsinjektions-Framework wie Hilt verwenden, das Objekte und Abhängigkeiten erstellt, wenn diese zum ersten Mal eingeschleust werden.

Wenn Ihre App Inhaltsanbieter zum Initialisieren von App-Komponenten beim Start verwendet, sollten Sie stattdessen die App-Start-up-Bibliothek verwenden.

Initialisierung wegen intensiver Aktivität

Das Erstellen von Aktivitäten ist oft mit einem hohen Aufwand verbunden. Häufig gibt es Möglichkeiten, diese Arbeit zu optimieren, um Leistungsverbesserungen zu erzielen. Zu diesen häufigen Problemen gehören:

  • Das Aufblähen großer oder komplexer Layouts
  • Bildschirmzeichnung auf dem Laufwerk oder der Netzwerk-E/A wird blockiert.
  • Bitmaps laden und decodieren.
  • VectorDrawable-Objekte rastern.
  • Initialisierung anderer Subsysteme der Aktivität.

Problem diagnostizieren

In diesem Fall können sowohl das Methoden-Tracing als auch das Inline-Tracing nützlich sein.

Methoden-Tracing

Achten Sie bei Verwendung des CPU-Profilers auf die untergeordneten Application-Konstruktoren und com.example.customApplication.onCreate()-Methoden Ihrer Anwendung.

Wenn das Tool anzeigt, dass die Ausführung dieser Methoden sehr lange dauert, prüfen Sie weiter, welche Arbeit dort erfolgt.

Inline-Tracing

Verwenden Sie Inline-Tracing, um mögliche Ursachen zu untersuchen, z. B.:

  • Anfängliche onCreate()-Funktion deiner App.
  • Alle globalen Singleton-Objekte, die initialisiert werden.
  • Jede Laufwerk-E/A, Deserialisierung oder enge 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 Lösungen sind folgende:

  • Je größer die Ansichtshierarchie ist, desto mehr Zeit benötigt die App, sie aufzublähen. Mit den folgenden zwei Schritten kannst du dieses Problem beheben:
    • Die Ansichtshierarchie vereinfachen, indem Sie redundante oder verschachtelte Layouts reduzieren.
    • Bereiche der Benutzeroberfläche, die während des Starts nicht sichtbar sein müssen, dürfen nicht aufgeblasen werden. Verwenden Sie stattdessen ein ViewStub-Objekt als Platzhalter für Unterhierarchien, die von der App zu einem geeigneten Zeitpunkt aufgebläht werden können.
  • Wenn sich die gesamte Ressourceninitialisierung im Hauptthread befindet, kann dies den Start verlangsamen. Sie können dieses Problem so beheben:
    • Verschieben Sie die gesamte Ressourceninitialisierung, damit die Anwendung diese in einem anderen Thread verzögert ausführen kann.
    • Lasse die Anwendung deine Ansichten laden und anzeigen und aktualisiere dann später die visuellen Eigenschaften, die von Bitmaps und anderen Ressourcen abhängen.

Individuelle Ladebildschirme

Möglicherweise wird beim Start zusätzliche Zeit hinzugefügt, wenn du zuvor eine der folgenden Methoden verwendet hast, um einen benutzerdefinierten Ladebildschirm in Android 11 (API-Level 30) oder früher zu implementieren:

  • Verwendung des Designattributs windowDisablePreview, um den ersten leeren Bildschirm auszuschalten, der vom System beim Start angezeigt wird.
  • Dedizierte Activity verwenden.

Ab Android 12 ist die Migration zur SplashScreen API erforderlich. Diese API ermöglicht eine schnellere Startzeit und ermöglicht Ihnen, den Ladebildschirm so anzupassen:

Darüber hinaus rückt die Compat-Bibliothek die SplashScreen API zurück, um Abwärtskompatibilität zu gewährleisten und ein einheitliches Erscheinungsbild des Ladebildschirms in allen Android-Versionen zu schaffen.

Weitere Informationen