Wenn Sie nicht vorsichtig sind, können Bilder schnell zu Leistungsproblemen führen. Selbst eine kleine Grafik in einem komprimierten Format wie JPG oder PNG kann sich in eine große Bitmap verwandeln, wenn sie für die Anzeige dekodiert wird. Wenn Sie Grafiken nicht effizient verwenden, können Arbeitsspeicherprobleme auftreten, die die Leistung Ihrer App und anderer Apps auf dem Gerät beeinträchtigen. Mit diesen Best Practices sorgen Sie dafür, dass Ihre App optimal funktioniert.
Bibliotheken zum Laden von Bildern verwenden
Sie können die Effizienz Ihrer App verbessern, indem Sie Bibliotheken zum Laden von Bildern wie Coil (für Kotlin-basierte Projekte) oder Glide (für Java-Projekte) verwenden. Diese Bibliotheken reduzieren die Arbeitsspeichernutzung Ihrer App, indem sie beispielsweise Bilder im Cache speichern, Grafiken bei Bedarf herunterskalieren und Grafikobjekte wiederverwenden.
Bilder herunterskalieren
Verwenden Sie die für Ihre Anforderungen geeignete Bildgröße. Sie sollten kein großes Bild mit hoher Auflösung in einen kleinen Container (z. B. ein Thumbnail) laden. Verwenden Sie stattdessen Downsampling, um das Bild herunterskalieren, bevor Sie es in den Arbeitsspeicher dekodieren.
Clientseitiges Downsampling
Bibliotheken zum Laden von Bildern wie Coil und Glide übernehmen das Downsampling automatisch für Sie. Sie können die Downsampling-Strategien
mit ImageLoader (für Coil) oder DownsampleStrategy
(für Glide) konfigurieren. Wenn Sie Bitmaps manuell verwalten, können Sie mit
inSampleSize eine kleinere Version dekodieren. Dazu müssen Sie zuerst
inJustDecodeBounds auf true setzen, um die Bildabmessungen
zu lesen, ohne Arbeitsspeicher zuzuweisen. Berechnen Sie dann die Stichprobengröße, setzen Sie inSampleSize auf
diesen Wert, setzen Sie inJustDecodeBounds auf false und dekodieren Sie das Bild.
Serverseitige Größenänderung bevorzugen
Fordern Sie nach Möglichkeit die genauen Bildabmessungen, die Sie benötigen, direkt von Ihrem Back-End-Server an. Dadurch wird die Netzwerknutzung und der Speicherbedarf des Datenträger-Cache reduziert und gleichzeitig die Arbeitsspeichernutzung verringert, da der Arbeitsspeicher-Aufwand für die Größenänderung von Bildern auf dem Gerät vermieden wird.
Sie können Bibliotheken so konfigurieren, dass die Größe der Zielansicht dynamisch an die Bild-URL angehängt wird. Mit Coil ist dies beispielsweise mit benutzerdefinierten Interceptors möglich und Glide unterstützt es mit benutzerdefinierten Modell-Loadern (z. B. BaseGlideUrlLoader).
Unbeschränkte Layoutgrößen vermeiden
Damit Bild-Loader Bilder effektiv herunterskalieren können (clientseitig oder serverseitig), müssen sie die Zielgröße vor der Ausführung der Anfrage kennen.
Verwenden Sie nicht wrapContentSize und lassen Sie die Abmessungen nicht unbeschränkt für Composables, die Remote-Bilder laden. Wenn diese Bibliotheken die Zielbegrenzungen nicht ableiten können, laden sie das ursprüngliche Bild in voller Größe.
Dies kann dazu führen, dass ein wesentlich größeres Bild als nötig geladen wird, was die Arbeitsspeichernutzung und die Latenz erhöht.
Legen Sie stattdessen explizite Abmessungen für Ihr Bild-Composable fest (z. B. mit Modifier.size) oder definieren Sie ein Seitenverhältnis. So kann die Layout-Engine die genaue Pixelzielgröße im Voraus berechnen, die das Bild-Ladeprogramm dann verwenden kann, um das Asset in der richtigen Größe anzufordern und zu decodieren.
Alternative Ressourcen für verschiedene Bildschirmgrößen bereitstellen
Wenn Sie Bilder mit Ihrer App ausliefern, sollten Sie Assets in verschiedenen Größen für unterschiedliche Geräteauflösungen bereitstellen. So können Sie die Downloadgröße Ihrer App auf Geräten reduzieren und die Leistung verbessern, da auf Geräten mit niedrigerer Auflösung ein Bild mit niedrigerer Auflösung geladen wird. Weitere Informationen zum Bereitstellen alternativer Bitmaps für verschiedene Gerätegrößen finden Sie in der Dokumentation zu alternativen Bitmaps.
Padding nicht direkt anwenden
Manchmal müssen Sie einem Bild Padding hinzufügen. Beispielsweise möchten Sie möglicherweise, dass das Bild von einem transparenten Rahmen umgeben ist, um Letterboxing zu erzielen.
In diesen Fällen dürfen Sie das Padding nicht direkt dem Bild hinzufügen, da sich dadurch die Abmessungen
des Bildes ändern. Lassen Sie stattdessen die Abmessungen des Bildes unverändert,
und passen Sie die Position des Bildes auf dem Bildschirm mit InsetDrawable an.
Alternativ können Sie dem Composable oder der Ansicht, die das Bild enthält, Padding hinzufügen.
Das richtige Pixelformat auswählen
Wählen Sie das richtige Pixelformat, um ein Gleichgewicht zwischen Arbeitsspeicher und Qualität zu finden. Verwenden Sie RGB_565, wenn Sie keine Transparenz benötigen. Dieses Format verwendet nur halb so viel Arbeitsspeicher wie das Standardformat ARGB_8888.
In Glide können Sie dies mit DecodeFormat konfigurieren. In Coil können Sie die
bitmapConfig Eigenschaft verwenden.
Nach Möglichkeit Vektoren verwenden
Bei Bildern, die aus geometrischen Formen bestehen, ist eine Vektorgrafik viel kleiner als eine Bitmap und lässt sich für jede Anzeigedichte reibungslos skalieren. Verwenden Sie nach Möglichkeit Elemente
wie ShapeDrawable, um Grafiken darzustellen.
Bitmaps freigeben und wiederverwenden
Große Grafikdateien können viel Arbeitsspeicher belegen. Um die Auswirkungen zu reduzieren, sollten Sie die Grafikobjekte nach Möglichkeit freigeben oder wiederverwenden.
Wenn Sie eine Bibliothek zum Laden von Bildern verwenden, geben Sie Bitmaps für den verwalteten Pool der Bibliothek frei, wenn Sie sie nicht mehr benötigen. Die Bibliothek kann die Objekte bei Bedarf wiederverwenden und hält einen Arbeitsspeicherpuffer für zukünftige Anforderungen bereit.
Wenn Sie Grafiken manuell verwalten, sollten Sie Bitmaps freigeben, wenn Sie sie nicht mehr benötigen. Rufen Sie dazu Bitmap.recycle auf und verwerfen Sie sofort die Bitmap Referenz, anstatt sich auf die automatische Speicherbereinigung zu verlassen.
Weitere Tipps und Tricks
In diesem Abschnitt werden einige weitere Möglichkeiten beschrieben, die Leistung Ihrer App bei der Verarbeitung von Grafiken zu verbessern.
Keine großen Bilder in die AAB-/APK-Datei packen
Einer der Hauptgründe für eine große App-Downloadgröße sind Grafiken, die in der AAB- oder APK-Datei enthalten sind. Mit dem APK Analyzer können Sie prüfen, ob Sie keine größeren Bilddateien als erforderlich verpacken. Reduzieren Sie die Größe oder platzieren Sie die Bilder auf einem Server und laden Sie sie nur bei Bedarf herunter.
Redundante Bitmaps suchen
Wenn Sie mehrere Kopien desselben Bildes haben, wird Arbeitsspeicher verschwendet. Mit dem Android Studio Profiler können Sie redundante Grafiken identifizieren. Verwenden Sie den Heap-Dump Analyzer, um einen Heap-Dump zu erfassen, und filtern Sie die Ergebnisse, indem Sie die Einstellung „Duplicate bitmaps“ (Doppelte Bitmaps) auswählen.
Bei Verwendung von ImageBitmap vor dem Zeichnen prepareToDraw aufrufen
Wenn Sie ImageBitmap verwenden, rufen Sie ImageBitmap#prepareToDraw() auf, bevor Sie das Bild zeichnen, um den Prozess des Hochladens der Textur auf die
GPU zu starten. So kann die GPU die Textur vorbereiten und die Leistung bei der Anzeige eines visuellen Elements auf dem Bildschirm verbessern. Die meisten Bibliotheken zum Laden von Bildern führen diese Optimierung bereits durch. Wenn Sie jedoch selbst mit der Klasse ImageBitmap arbeiten, sollten Sie dies berücksichtigen.
Statt Painter eine Int DrawableRes oder URL als Parameter an Ihr Composable übergeben
Aufgrund der Komplexität des Umgangs mit Bildern (z. B. wäre das Schreiben einer Gleichheits
funktion für Bitmaps rechenintensiv) ist die Painter API mit der @Stable
Annotation nicht
explizit als stabil gekennzeichnet. Instabile Klassen können zu unnötigen Neukompositionen führen, da der Compiler nicht einfach ableiten kann, ob sich die Daten geändert haben.
Daher empfehlen wir, eine URL oder eine ID der zeichenfähigen Ressource als Parameter an Ihre komponierbare Funktion zu übergeben, anstatt Painter als Parameter zu übergeben.
// Prefer this:
@Composable
fun MyImage(url: String) {
}
// Over this:
@Composable
fun MyImage(painter: Painter) {
}
Persönliche Empfehlungen
- Hinweis: Linktext wird angezeigt, wenn JavaScript deaktiviert ist
- Vergleich von ImageBitmap mit ImageVector {:#bitmap-vs-vector}
- UI-Status in Compose speichern
- Jetpack Compose-Phasen