Nutzer erwarten, dass Apps schnell geladen werden und responsiv sind. Eine App mit einer langsamen Startzeit erfüllt diese Erwartung nicht und kann Nutzer enttäuschen. Eine solche schlechte Nutzererfahrung kann dazu führen, dass ein Nutzer deine App im Google Play Store schlecht bewertet oder sie sogar ganz aufgibt.
Auf dieser Seite finden Sie Informationen zur Optimierung der Startzeit Ihrer App, einschließlich einer Übersicht über die internen Abläufe des Startvorgangs, Informationen zur Profilerstellung der Startleistung und einige häufige Probleme mit der Startzeit sowie Tipps zu deren Behebung.
Die verschiedenen Startzustände von Apps
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 die App von Grund auf neu gestartet. In den anderen Zuständen muss das System die laufende App vom Hintergrund in den Vordergrund bringen.
Wir empfehlen, immer auf der Grundlage eines Kaltstarts zu optimieren. Dadurch kann auch die Leistung von Warm- und Heißstarts verbessert werden.
Wenn du deine App für einen schnellen Start optimieren möchtest, ist es hilfreich zu wissen, was auf System- und App-Ebene passiert und wie sie in den einzelnen Zuständen interagieren.
Zwei wichtige Messwerte für den App-Start sind die Zeit bis zur ersten Anzeige (TTID) und die Zeit bis zur vollständigen Anzeige (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 die TTID dem Nutzer signalisiert, dass die App geladen wird, und die TTFD angibt, wann die App tatsächlich verwendet werden kann. Wenn einer dieser Vorgänge zu lange dauert, verlässt der Nutzer Ihre App möglicherweise, bevor sie 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 Systemprozess den App-Prozess erstellt. Kaltstarts treten beispielsweise auf, wenn Ihre App zum ersten Mal seit dem Starten des Geräts oder seit dem Beenden der App durch das System gestartet wird.
Diese Art von Start stellt die größte Herausforderung bei der Minimierung der Startzeit dar, da das System und die App mehr Arbeit als in den anderen Startzuständen haben.
Zu Beginn eines Kaltstarts hat das System die folgenden drei Aufgaben:
- Lade die App und starte sie.
- Direkt nach dem Start der App ein leeres Startfenster anzeigen.
- Erstellen Sie den Prozess für die App.
Sobald das System den App-Prozess erstellt hat, ist der App-Prozess für die nächsten Phasen verantwortlich:
- Erstellen Sie das App-Objekt.
- Starte den Hauptthread.
- Erstellen Sie die Hauptaktivität.
- Initialisieren Sie die Benutzeroberfläche.
- Zeichnen Sie die Benutzeroberfläche auf dem Bildschirm.
Wenn der App-Prozess das erste Zeichnen 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 beim Erstellen der App und der Hostaktivität auftreten.
App-Erstellung
Wenn deine App gestartet wird, bleibt das leere Startfenster auf dem Bildschirm, bis das System die App zum ersten Mal vollständig dargestellt hat. An diesem Punkt tauscht der Systemprozess das Startfenster gegen deine 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 als UI-Thread bezeichnet, erstellt und mit der Erstellung der Hostaktivität Ihrer App beauftragt.
Ab diesem Punkt werden Prozesse auf System- und App-Ebene gemäß den Phasen des App-Lebenszyklus ausgeführt.
Aktivität erstellen
Nachdem der App-Prozess die Aktivität erstellt hat, führt die Aktivität die folgenden Vorgänge aus:
- Initialisiert Werte.
- Ruft Konstruktoren auf.
- Ruft die Callback-Methode auf, z. B.
Activity.onCreate, die dem aktuellen Lebenszyklusstatus der Aktivität entspricht.
In der Regel hat die Methode onCreate die größten Auswirkungen auf die Ladezeit. In einer Jetpack Compose-Anwendung wird der Overhead der onCreate-Methode häufig durch die anfängliche Komposition verursacht. Das passiert, wenn Ihre App setContent aufruft und Ihre Composables auf oberster Ebene aufruft. Eine tiefe oder komplexe UI-Hierarchie oder Composables, die aufwendige Berechnungen im Hauptthread ausführen, können diese Zusammensetzungszeit erhöhen.
Warm start
Ein Warmstart umfasst einen Teil der Vorgänge, die während eines Kaltstarts stattfinden. Gleichzeitig ist der Aufwand höher als bei einem Warmstart. Es gibt viele potenzielle Zustände, die als Warmstarts betrachtet werden können, z. B.:
Der Nutzer verlässt Ihre App, startet sie dann aber neu. Der Prozess wird möglicherweise fortgesetzt, aber die App muss die Aktivität mit einem Aufruf von
onCreateneu erstellen.Das System entfernt Ihre App aus dem Arbeitsspeicher und der Nutzer startet sie neu. Der Prozess und die Aktivität müssen neu gestartet werden, aber die Aufgabe kann in gewissem Maße von dem gespeicherten Instanzstatus-Bundle profitieren, das an
onCreateübergeben wird.
Heißstart
Ein Heißstart Ihrer App ist mit weniger Aufwand verbunden als ein Kaltstart. Bei einem Warmstart 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 Wiederholung der Objektinitialisierung, der UI-Initialisierung und des Renderings vermeiden.
Wenn jedoch ein Teil des Arbeitsspeichers als Reaktion auf Ereignisse zur Speicherbereinigung wie onTrimMemory gelöscht wird, müssen diese Objekte als Reaktion auf das Warmstartereignis neu erstellt werden.
Ein Warmstart zeigt dasselbe Verhalten auf dem Bildschirm wie ein Kaltstart. Der Systemprozess zeigt einen leeren Bildschirm an, bis die App das Rendern der Aktivität abgeschlossen hat.
App-Start in Perfetto identifizieren
Um Probleme beim App-Start zu beheben, ist es hilfreich, genau zu bestimmen, was in der App-Startphase enthalten ist. So identifizieren Sie die gesamte App-Startphase in Perfetto:
Suchen Sie in Perfetto nach der Zeile mit dem abgeleiteten Messwert „Android App Startups“. Wenn Sie ihn nicht sehen, versuchen Sie, einen Trace mit der System-Tracing-App auf dem Gerät zu erfassen.
Abbildung 2. Das abgeleitete Messwert-Slice „Android App Startups“ in Perfetto. Klicken Sie auf das entsprechende Segment und drücken Sie m, um es auszuwählen. Um das Segment herum werden Klammern angezeigt, die angeben, wie lange es gedauert hat. Die Dauer wird auch auf dem Tab Aktuelle Auswahl angezeigt.
Pinnen Sie die Zeile „Android App Startups“ an, indem Sie auf das Stecknadelsymbol klicken, das angezeigt wird, wenn Sie den Mauszeiger auf die Zeile bewegen.
Scrollen Sie zur Zeile mit der betreffenden App und klicken Sie auf die erste Zelle, um die Zeile zu maximieren.
Zoomen Sie in den Hauptthread, der sich normalerweise oben befindet, indem Sie w drücken. Drücken Sie s, a, d, um herauszuzoomen, sich nach links oder nach rechts zu bewegen.
Abbildung 3. Das Segment für den abgeleiteten Messwert „Android App Startups“ neben dem Hauptthread der App. Im Bereich für abgeleitete Messwerte ist leichter zu erkennen, was genau im App-Start enthalten ist. So kannst du das Debugging detaillierter fortsetzen.
Wenn Sie eine Jetpack Compose-Anwendung analysieren, können Sie mit dem Composition-Tracing detaillierte Informationen zur Leistung Ihrer Benutzeroberfläche abrufen.
Achten Sie besonders auf Trace-Abschnitte im Hauptthread, die mit Choreographer#doFrame beginnen. Suchen Sie nach Slices wie Compose:recompose, Compose:layout und Compose:draw. Diese zeigen Ihnen, 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 diagnostizieren, können Sie Messwerte erfassen, die zeigen, wie lange es dauert, bis Ihre App gestartet wird. Android bietet mehrere Möglichkeiten, um Ihnen zu zeigen, dass ein Problem mit Ihrer App vorliegt, und hilft Ihnen bei der Diagnose.
Vorteile der Verwendung von Startmesswerten
Android verwendet die Messwerte Zeit bis zur ersten Anzeige (TTID) und Zeit bis zur vollständigen Anzeige (TTFD), um Kalt- und Warmstarts von Apps zu optimieren. Android Runtime (ART) verwendet die Daten aus diesen Messwerten, um Code effizient vorzukompilieren und zukünftige Starts zu optimieren.
Schnellere Starts führen zu einer nachhaltigeren Nutzerinteraktion mit Ihrer App, wodurch die Anzahl der vorzeitigen Beendigungen, Neustarts der Instanz oder Wechsel zu einer anderen App reduziert wird.
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. Dieser Messwert gibt an, wie lange es dauert, bis eine App den ersten Frame erzeugt. Dazu gehören die Prozessinitialisierung bei einem Kaltstart, die Erstellung von Aktivitäten bei einem Kalt- oder Warmstart und die Anzeige des ersten Frames. Wenn die TTID Ihrer App niedrig ist, wird die Nutzerfreundlichkeit verbessert, da die App schnell gestartet wird. Die TTID wird vom Android-Framework automatisch für jede App gemeldet. Wenn Sie den App-Start optimieren möchten, empfehlen wir, reportFullyDrawn zu implementieren, um Informationen bis zur TTFD zu erhalten.
Die TTID wird als Zeitwert gemessen, der die insgesamt verstrichene Zeit darstellt, die die folgende Abfolge von Ereignissen umfasst:
- Prozess wird gestartet.
- Objekte werden initialisiert.
- Hostaktivität wird erstellt und initialisiert.
- Die Benutzeroberfläche wird initialisiert.
- Die App wird zum ersten Mal gezeichnet.
TTID abrufen
Wenn du die TTID ermitteln möchtest, suche im Logcat-Befehlszeilentool nach einer Ausgabezeile, die einen Wert namens Displayed enthält. Dieser Wert ist die TTID und sieht in etwa so aus wie im folgenden Beispiel, in dem die TTID 3s534ms beträgt:
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, wie in Abbildung 4 dargestellt.
Das Deaktivieren der Filter ist erforderlich, da dieses Protokoll vom Systemserver und nicht von der App selbst bereitgestellt wird.
Displayed in Logcat.Der Messwert Displayed in der Logcat-Ausgabe erfasst nicht unbedingt die Zeit, bis alle Ressourcen geladen und angezeigt werden. Ressourcen, die nicht in der ursprünglichen Komposition referenziert werden (z. B. asynchron geladene Daten oder Bilder), oder Ressourcen, die die App im Rahmen der Objektinitialisierung erstellt, werden weggelassen. Diese Ressourcen werden ausgeschlossen, da sie inline geladen werden und die Erstanzeige der App nicht blockieren.
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 gilt die erste Zeitmessung nur für die Aktivität, die zuerst gezeichnet wird, in der Regel die Hostaktivitä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 der Zeit für die einzelne Aktivität und der Gesamtstartzeit 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 adb-Shell-Activity-Manager-Befehl 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 zuvor in der Logcat-Ausgabe 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 App benötigt, um für den Nutzer interaktiv zu werden. Sie wird als die Zeit angegeben, die benötigt wird, um den ersten Frame der Benutzeroberfläche der App sowie den Inhalt anzuzeigen, der nach der Anzeige des ersten Frames asynchron geladen wird. In der Regel handelt es sich dabei um primäre Inhalte, die aus dem Netzwerk oder vom Laufwerk geladen werden, wie von der App gemeldet. Mit anderen Worten: TTFD umfasst TTID sowie die Zeit, die die App benötigt, um nutzbar zu sein. 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 bestimmen, wenn das Hostfenster den ersten Frame rendert, die TTFD kann jedoch nicht automatisch bestimmt 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 die TTFD zu bestimmen, muss die App dem System signalisieren, wenn sie den vollständig gezeichneten Zustand erreicht hat.
TTFD abrufen
Wenn Sie die TTFD ermitteln möchten, signalisieren Sie den vollständig gezeichneten Zustand, indem Sie die Methode reportFullyDrawn von ComponentActivity aufrufen. Die Methode reportFullyDrawn meldet, wenn die App vollständig gerendert wurde und sich in einem nutzbaren Zustand befindet. Die TTFD ist die Zeit, die vergeht, bis das System den Intent zum Starten der App empfängt und reportFullyDrawn aufgerufen wird. Wenn Sie reportFullyDrawn nicht aufrufen, wird kein TTFD-Wert gemeldet.
Wenn Sie die TTFD messen möchten, rufen Sie reportFullyDrawn auf, nachdem die Benutzeroberfläche und alle Daten vollständig dargestellt wurden. Rufe reportFullyDrawn nicht auf, bevor das Fenster der ersten Aktivität zum ersten Mal gezeichnet und angezeigt wird, wie vom System gemessen, da das System dann die vom System gemessene Zeit meldet. Wenn Sie also reportFullyDrawn aufrufen, bevor das System die TTID erkennt, meldet das System sowohl die TTID als auch die TTFD als denselben Wert. Dieser Wert ist der TTID-Wert.
Wenn Sie reportFullyDrawn verwenden, zeigt Logcat eine Ausgabe wie im folgenden Beispiel an, 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 unter Zeit bis zur ersten Anzeige beschrieben.
Wenn die Anzeigezeiten langsamer als gewünscht sind, können Sie versuchen, die Engpässe im Startvorgang zu identifizieren.
In einfachen Fällen, in denen Sie wissen, dass der vollständig gezeichnete Zustand erreicht ist, können Sie reportFullyDrawn verwenden, um den vollständig gezeichneten Zustand zu signalisieren. In Fällen, in denen Hintergrundthreads jedoch Hintergrundarbeiten abschließen müssen, bevor der vollständig gezeichnete 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.
Genauigkeit des Startzeitpunkts verbessern
Wenn Ihre App Lazy Loading ausführt und die Erstanzeige 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 einbeziehen können.
Wenn die Benutzeroberfläche beispielsweise eine dynamische Liste wie LazyColumn oder LazyRow enthält, wird diese möglicherweise von einer Hintergrundaufgabe ausgefüllt, die abgeschlossen wird, nachdem die Liste zum ersten Mal gezeichnet wurde und somit nachdem die Benutzeroberfläche als vollständig gezeichnet markiert wurde. In solchen Fällen wird die Listenpopulation nicht in das Benchmarking einbezogen.
Wenn Sie die Listenpopulation in die Benchmark-Zeit einbeziehen möchten, rufen Sie die FullyDrawnReporter mit fullyDrawnReporter ab und fügen Sie ihr im App-Code einen Reporter hinzu. Geben Sie den Reporter frei, nachdem die Liste durch die Hintergrundaufgabe 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, stellen Sie sicher, dass die Startzeitdaten die Zeit für das Auffüllen der Liste enthalten, ohne das Verhalten der App für den Nutzer zu ändern. reportFullyDrawn wird erst aufgerufen, wenn alle Aufgaben abgeschlossen sind, unabhängig von der Reihenfolge.
Wenn Ihre App Jetpack Compose verwendet, können Sie die folgenden APIs verwenden, um den Status „Vollständig gezeichnet“ anzugeben:
ReportDrawn: Gibt an, dass Ihre zusammensetzbare Funktion sofort für die Interaktion bereit ist.ReportDrawnWhen: Akzeptiert ein Prädikat, z. B.list.count > 0, um anzugeben, wann die zusammensetzbare Funktion für die Interaktion bereit ist.ReportDrawnAfter: Verwendet eine Methode zum Pausieren, die nach Abschluss angibt, dass die zusammensetzbare Funktion für die Interaktion bereit ist.
Das folgende Beispiel zeigt, wie Sie mehrere Hintergrundaufgaben gleichzeitig ausführen können, wobei jede Aufgabe einen 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 dem CPU-Profiler prüfen.
Außerdem können Sie durch Inline-Tracing in den onCreate-Methoden Ihrer Apps und Aktivitäten Einblicke in potenzielle Engpässe erhalten. Weitere Informationen zum Inline-Tracing finden Sie in der Dokumentation zu den Trace-Funktionen und in der Übersicht über das System-Tracing.
Häufige Probleme beheben
In diesem Abschnitt werden mehrere 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 bei der Initialisierung dieses Objekts komplexe Logik ausführt oder umfangreiche Aufgaben erledigt. Ihre App verschwendet möglicherweise Zeit beim Start, wenn Ihre Application-Unterklassen Initialisierungen durchfü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 einen Teil der zuvor initialisierten Zustandsdaten.
Weitere Herausforderungen bei der App-Initialisierung sind Garbage-Collection-Ereignisse, die sich stark auswirken oder zahlreich sind, oder Laufwerk-E/A-Vorgänge, die gleichzeitig mit der Initialisierung stattfinden und den Initialisierungsprozess weiter blockieren. Die automatische Speicherbereinigung ist insbesondere bei der Dalvik-Laufzeitumgebung ein wichtiger Aspekt. Die Android Runtime (ART) führt die automatische Speicherbereinigung gleichzeitig aus, wodurch die Auswirkungen dieses Vorgangs minimiert werden.
Problem diagnostizieren
Sie können versuchen, das Problem mithilfe von Methoden-Tracing oder Inline-Tracing zu diagnostizieren.
Methoden-Tracing
Wenn Sie den CPU-Profiler ausführen, sehen Sie, dass die Methode callApplicationOnCreate schließlich die Methode com.example.customApplication.onCreate aufruft. Wenn das Tool zeigt, dass die Ausführung dieser Methoden lange dauert, sollten Sie sich genauer ansehen, welche Arbeit dort ausgeführt wird.
Inline-Tracing
Verwenden Sie Inline-Tracing, um wahrscheinliche Ursachen zu untersuchen, einschließlich der folgenden:
- Die anfängliche
onCreate-Funktion Ihrer App. - Alle globalen Singleton-Objekte, die Ihre Anwendung initialisiert.
- Alle Laufwerk-E/A-, Deserialisierungs- oder engen Schleifen, die während des Engpasses auftreten können.
Lösungen für das Problem
Unabhängig davon, ob das Problem bei unnötigen Initialisierungen oder bei der Laufwerk-E/A liegt, ist die Lösung die verzögerte Initialisierung. Mit anderen Worten: Initialisieren Sie nur Objekte, die sofort benötigt werden. Anstatt globale statische Objekte zu erstellen, sollten Sie ein Singleton-Muster verwenden, bei dem die Anwendung Objekte nur dann initialisiert, wenn sie sie zum ersten Mal benötigt.
Außerdem sollten Sie 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 in deiner App Contentanbieter verwendet werden, um App-Komponenten beim Start zu initialisieren, solltest du stattdessen die App Startup-Bibliothek verwenden.
Initialisierung bei starker Aktivität
Das Erstellen von Aktivitäten ist oft mit viel Aufwand verbunden. Häufig gibt es Möglichkeiten, diese Arbeit zu optimieren, um Leistungsverbesserungen zu erzielen. Zu diesen häufigen Problemen gehören:
- Initialisieren einer großen oder komplexen Benutzeroberfläche.
- Aufwendige Initialisierung in Composables.
- Blockieren des Zeichnens auf dem Bildschirm auf dem Laufwerk oder der Netzwerk-E/A.
- 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 Methoden- als auch Inline-Tracing nützlich sein.
Methoden-Tracing
Achten Sie bei der Verwendung des CPU-Profilers auf die Application-Unterklassenkonstruktoren und com.example.customApplication.onCreate-Methoden Ihrer App.
Wenn das Tool zeigt, dass die Ausführung dieser Methoden lange dauert, sollten Sie sich genauer ansehen, was dort passiert.
Inline-Tracing
Verwenden Sie Inline-Tracing, um wahrscheinliche Ursachen zu untersuchen, darunter:
- Die anfängliche
onCreate-Funktion Ihrer App. - Alle globalen Singleton-Objekte, die initialisiert werden.
- Alle Laufwerk-E/A-, Deserialisierungs- 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 hat.
Gehen Sie so vor:
- Vereinfachen Sie die UI-Hierarchie, indem Sie redundante oder verschachtelte Composables reduzieren.
- Vermeiden Sie unnötige Kompositionen und Neukompositionen während des Starts.
- Zusammensetzung von nicht kritischen UI-Elementen verzögern.
- Wenn alle Ressourcen im Hauptthread initialisiert werden, kann dies ebenfalls den 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 Sie die Benutzeroberfläche zuerst mit Platzhalterdaten und zeigen Sie sie an. Aktualisieren Sie dann später die visuellen Eigenschaften, die von Bitmaps und anderen Ressourcen abhängen.
Weitere Informationen zur Neuzusammensetzung finden Sie unter Neuzusammensetzung und Anzahl der Neuzusammensetzungen abrufen.
Benutzerdefinierte Ladebildschirme
Wenn Sie zuvor eine der folgenden Methoden verwendet haben, um einen benutzerdefinierten Splash Screen in Android 11 (API-Level 30) oder niedriger zu implementieren, kann es beim Start zu einer Verzögerung kommen:
- Verwendung des Designattributs
windowDisablePreview, um den anfänglichen leeren Bildschirm zu deaktivieren, der beim Start vom System angezeigt wird. - Verwenden Sie einen dedizierten
Activity.
Ab Android 12 ist die Migration zur SplashScreen API erforderlich.
Diese API ermöglicht eine schnellere Startzeit und bietet folgende Möglichkeiten, den Splash Screen anzupassen:
- Legen Sie ein Design fest, um das Erscheinungsbild des Splash Screens zu ändern.
- Mit
windowSplashScreenAnimationDurationkönnen Sie festlegen, wie lange der Splash Screen angezeigt wird. - Passen Sie die Animation des Splash Screens an und sorgen Sie für eine reibungslose Animation beim Schließen des Splash Screens.
Außerdem wird die SplashScreen API in der Kompatibilitätsbibliothek zurückportiert, um die Abwärtskompatibilität zu ermöglichen und ein einheitliches Erscheinungsbild für die Anzeige des Splash Screens in allen Android-Versionen zu schaffen.
Weitere Informationen finden Sie in der Migrationsanleitung für Splash Screens.
Empfehlungen für Sie
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Langsames Rendering
- Makro-Benchmark-Messwerte erfassen
- Baseline-Profile erstellen{:#creating-profile-rules}