Wenn Sie nicht vorsichtig sind, kann die Arbeit mit Bildern schnell zu Leistungsproblemen führen. Selbst eine kleine Grafik in einem komprimierten Format wie JPG oder PNG kann beim Decodieren für die Anzeige zu einer großen Bitmap werden. Wenn Sie Grafiken nicht effizient nutzen, kann es zu Arbeitsspeicherproblemen kommen, die die Leistung Ihrer App und anderer Apps auf dem Gerät beeinträchtigen können. Mit diesen Best Practices können Sie die Leistung Ihrer App optimieren.
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-First-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 heruntersampeln
Achten Sie darauf, die für Ihre Anforderungen geeignete Bildgröße zu verwenden. Sie sollten es vermeiden, ein großes, hochauflösendes Bild in einen kleinen Container (z. B. ein Thumbnail) zu laden. Verwenden Sie stattdessen Downsampling, um das Bild zu verkleinern, bevor Sie es im Arbeitsspeicher decodieren.
Clientseitiges Downsampling
Bibliotheken zum Laden von Bildern wie Coil und Glide übernehmen das Downsampling automatisch für dich. 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 inSampleSize verwenden, um eine kleinere Version zu decodieren. Dazu sollten Sie zuerst inJustDecodeBounds auf true setzen, um die Bildabmessungen ohne Speicherzuweisung zu lesen, die Stichprobengröße zu berechnen, inSampleSize auf diesen Wert zu setzen, inJustDecodeBounds auf false zu setzen und dann das Bild zu decodieren.
Serverseitige Größenanpassung bevorzugen
Fordern Sie nach Möglichkeit die genauen Bildabmessungen, die Sie benötigen, direkt von Ihrem Backend-Server an. Dadurch werden die Netzwerknutzung und der Speicherbedarf des Datenträger-Caches reduziert. Außerdem wird die Arbeitsspeichernutzung verringert, da die Größe der Bilder nicht auf dem Gerät angepasst werden muss.
Sie können Bibliotheken so konfigurieren, dass die Zielansichtsgröße dynamisch an die Bild-URL angehängt wird. Coil ermöglicht dies beispielsweise mit benutzerdefinierten Interceptoren und Glide unterstützt es mit benutzerdefinierten Modellladern (z. B. BaseGlideUrlLoader).
Unbeschränkte Layoutgrößen vermeiden
Damit Bild-Ladeprogramme effektiv (clientseitig oder serverseitig) herunterskalieren können, müssen sie die Zielgröße vor der Ausführung der Anfrage kennen.
Vermeiden Sie die Verwendung von wrapContentSize oder die Angabe von unbegrenzten Dimensionen für Compose-Elemente, die Remote-Bilder laden. Wenn diese Bibliotheken die Zielgrenzen nicht ableiten können, wird das ursprüngliche Bild in voller Größe geladen.
Dies kann dazu führen, dass ein wesentlich größeres Image als nötig geladen wird, was die Arbeitsspeichernutzung und die Latenz erhöht.
Legen Sie stattdessen explizite Abmessungen für das Bild-Composable fest (z. B. mit Modifier.size) oder definieren Sie ein Seitenverhältnis. So kann die Layout-Engine das genaue Pixelziel im Voraus berechnen, das der Image Loader 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 bereitstellen, sollten Sie Assets in verschiedenen Größen für unterschiedliche Geräteauflösungen anbieten. So lässt sich die Downloadgröße Ihrer App auf Geräten reduzieren und die Leistung verbessern, da auf einem Gerät 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.
Kein Padding direkt anwenden
Manchmal müssen Sie einem Bild einen Innenabstand hinzufügen. Sie können das Bild beispielsweise mit einem transparenten Rahmen für Letterboxing umgeben.
In diesen Fällen solltet ihr 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 ausgewogenes Verhältnis zwischen Speicherplatz und Qualität zu erzielen. Verwenden Sie RGB_565, wenn Sie keine Transparenz benötigen. Dieses Format belegt nur halb so viel Speicher wie das Standardformat ARGB_8888.
In Glide können Sie dies mit DecodeFormat konfigurieren. In Coil können Sie das Attribut bitmapConfig 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 problemlos skalieren. Verwenden Sie gegebenenfalls Elemente wie ShapeDrawable, um Grafiken darzustellen.
Bitmaps nach Möglichkeit freigeben und wiederverwenden
Große Grafikdateien können viel Speicherplatz 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, müssen Sie Bitmaps im verwalteten Pool der Bibliothek freigeben, 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 den Verweis Bitmap, anstatt sich auf die automatische Speicherbereinigung zu verlassen.
Weitere Tipps und Tricks
In diesem Abschnitt werden einige weitere Möglichkeiten aufgeführt, wie Sie die Leistung Ihrer App bei der Verarbeitung von Grafiken verbessern können.
Fügen Sie Ihrer AAB-/APK-Datei keine großen Bilder hinzu.
Eine der Hauptursachen für große App-Downloadgrößen sind Grafiken, die in der AAB- oder APK-Datei enthalten sind. Verwenden Sie das Tool APK Analyzer, um sicherzustellen, dass 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 finden
Wenn Sie mehrere Kopien desselben Bildes haben, wird dadurch Speicherplatz verschwendet. Mit dem Profiler von Android Studio können Sie redundante Grafiken identifizieren. Verwenden Sie den Heap-Dump-Analysator, um einen Heap-Dump zu erfassen, und filtern Sie die Ergebnisse, indem Sie die Einstellung Doppelte Bitmaps auswählen.
Wenn Sie ImageBitmap verwenden, rufen Sie prepareToDraw vor dem Zeichnen auf.
Wenn Sie ImageBitmap verwenden, rufen Sie ImageBitmap#prepareToDraw() auf, bevor Sie die Textur zeichnen, um den Upload der Textur auf die GPU zu starten. So kann die GPU die Textur vorbereiten und die Leistung bei der Darstellung eines Bildes auf dem Bildschirm verbessern. Die meisten Bibliotheken zum Laden von Bildern führen diese Optimierung bereits durch. Wenn du jedoch selbst mit der Klasse ImageBitmap arbeitest, solltest du dies im Hinterkopf behalten.
Übergeben Sie am besten einen Int-DrawableRes oder eine URL als Parameter an Ihre zusammensetzbare Funktion, anstatt Painter zu verwenden.
Aufgrund der Komplexität des Umgangs mit Bildern (z. B. wäre das Schreiben einer Gleichheitsfunktion für Bitmaps rechenintensiv) wird die Painter API explizit nicht mit der Annotation @Stable als stabil gekennzeichnet. Instabile Klassen können zu unnötigen Neuzusammensetzungen führen, da der Compiler nicht einfach ableiten kann, ob sich die Daten geändert haben.
Wir empfehlen daher, eine URL oder eine ID einer zeichenfähigen Ressource als Parameter an die zusammensetzbare Funktion zu übergeben, anstatt ein Painter-Objekt als Parameter zu übergeben.
// Prefer this:
@Composable
fun MyImage(url: String) {
}
// Over this:
@Composable
fun MyImage(painter: Painter) {
}
Empfehlungen für Sie
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Vergleich von ImageBitmap mit ImageVector {:#bitmap-vs-vector}
- UI-Status in Compose speichern
- Jetpack Compose-Phasen