Hinweis:Es gibt mehrere Bibliotheken, die Best Practices für das Laden von Bildern. Sie können diese Bibliotheken in Ihrer App für Folgendes verwenden: Bilder so optimiert, dass sie optimal geladen werden. Wir empfehlen die Glide in der Bilder so schnell und reibungslos wie möglich geladen und angezeigt werden. Weitere beliebte Bibliotheken zum Laden von Bildern sind Picasso vom Square, Coil von Instacart und Fresco von Facebook. Diese Bibliotheken vereinfachen die meisten mit Bitmaps und anderen Bildern auf Android.
Bilder gibt es in allen möglichen Formen und Größen. In vielen Fällen sind sie größer als für eine typische Benutzeroberfläche (UI) der Anwendung. In der Systemgalerie-Anwendung werden z. B. Fotos angezeigt, Android-Geräte verwenden, deren Auflösung meist viel höher ist als die Bildschirmauflösung die Anzeigedichte von 50 Pixeln.
Da Sie mit begrenztem Speicher arbeiten, sollten Sie idealerweise nur eine niedrigere Auflösung laden. Version im Arbeitsspeicher. Die Version mit geringerer Auflösung sollte der Größe der UI-Komponente entsprechen, die wird es angezeigt. Ein Bild mit einer höheren Auflösung hat keinen sichtbaren Vorteil, nimmt aber dennoch und verursacht zusätzlichen Leistungs-Overhead aufgrund von zusätzlichem spontanem Skalierung.
In dieser Lektion erfahren Sie, wie Sie große Bitmaps decodieren, ohne das indem Sie eine kleinere Teilstichprobenversion in den Arbeitsspeicher laden.
Bitmapabmessungen und -typ lesen
Die Klasse BitmapFactory
bietet mehrere Decodierungsmethoden (decodeByteArray()
, decodeFile()
, decodeResource()
usw.) zum Erstellen einer Bitmap
aus verschiedenen Quellen. Auswählen
die sich am besten für Ihre Bilddatenquelle eignet. Mit diesen Methoden wird versucht,
Speicher für die erstellte Bitmap zuzuteilen und kann daher leicht zu einem OutOfMemory
führen.
Ausnahme. Jede Art von Decodierungsmethode verfügt über zusätzliche Signaturen, mit denen Sie die Decodierung festlegen können
Optionen über die Klasse BitmapFactory.Options
. Das Attribut inJustDecodeBounds
beim Decodieren auf true
festlegen
vermeidet Arbeitsspeicherzuweisung und gibt null
für das Bitmapobjekt zurück, legt aber outWidth
, outHeight
und outMimeType
fest. Mit dieser Technik können Sie die
Dimensionen und Typ der Bilddaten vor Erstellung (und Speicherzuweisung) der
Bitmap.
Kotlin
val options = BitmapFactory.Options().apply { inJustDecodeBounds = true } BitmapFactory.decodeResource(resources, R.id.myimage, options) val imageHeight: Int = options.outHeight val imageWidth: Int = options.outWidth val imageType: String = options.outMimeType
Java
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.id.myimage, options); int imageHeight = options.outHeight; int imageWidth = options.outWidth; String imageType = options.outMimeType;
Um java.lang.OutOfMemory
-Ausnahmen zu vermeiden, prüfen Sie die Abmessungen einer Bitmap vor dem
es nicht decodiert werden kann, es sei denn, Sie vertrauen der Quelle absolut hundertprozentig, um Bilddaten in vorhersehbarer Größe bereitzustellen
das bequem in den
verfügbaren Speicher passt.
Herunterskalierte Version in den Arbeitsspeicher laden
Jetzt, da die Bildabmessungen bekannt sind, können sie verwendet werden, um zu entscheiden, ob das vollständige Bild in den Arbeitsspeicher geladen werden soll oder ob stattdessen eine Subsampling-Version geladen werden soll. Hier sind einige Faktoren, sollten Sie Folgendes in Betracht ziehen:
- Geschätzte Arbeitsspeichernutzung beim Laden des vollständigen Bildes in den Arbeitsspeicher.
- Arbeitsspeichermenge, die Sie für das Laden dieses Images bei einem anderen Arbeitsspeicher zur Verfügung stellen möchten Anforderungen Ihrer Anwendung.
- Abmessungen des Ziel-
ImageView
oder der UI-Komponente, die das Bild enthält in das die Daten geladen werden sollen. - Bildschirmgröße und -dichte des aktuellen Geräts.
Es lohnt sich beispielsweise nicht, ein Bild mit 1024 x 768 Pixeln in den Speicher zu laden,
wird in einer Miniaturansicht mit 128 × 96 Pixeln in einem ImageView
angezeigt.
Um den Decodierer anzuweisen, das Bild durch das Laden einer kleineren Version in den Arbeitsspeicher zu übertragen, setzen Sie inSampleSize
in Ihrem BitmapFactory.Options
-Objekt auf true
. Beispiel: Ein Bild mit einer Auflösung von 2048 x 1536, das
mit einem inSampleSize
von 4 decodiert wird, erzeugt ein
Bitmap von etwa 512 x 384. Wenn diese Datei in den Arbeitsspeicher geladen wird, werden für die gesamte
(Bitmapkonfiguration von ARGB_8888
vorausgesetzt). Hier finden Sie
eine Methode zur Berechnung eines Stichprobengrößenwerts mit einer Potenz von zwei basierend auf einer Zielbreite und
Höhe:
Kotlin
fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int { // Raw height and width of image val (height: Int, width: Int) = options.run { outHeight to outWidth } var inSampleSize = 1 if (height > reqHeight || width > reqWidth) { val halfHeight: Int = height / 2 val halfWidth: Int = width / 2 // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while (halfHeight / inSampleSize >= reqHeight && halfWidth / inSampleSize >= reqWidth) { inSampleSize *= 2 } } return inSampleSize }
Java
public static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } return inSampleSize; }
Hinweis:Die Potenz von zwei wird berechnet, weil der Decoder
einen endgültigen Wert durch Abrunden auf die nächste Potenz von zwei, wie in der inSampleSize
-Dokumentation angegeben.
Um diese Methode zu verwenden, decodieren Sie zuerst, wobei inJustDecodeBounds
auf true
gesetzt ist, übergeben Sie die Optionen
und dann noch einmal mit dem neuen Wert inSampleSize
und inJustDecodeBounds
auf false
decodieren:
Kotlin
fun decodeSampledBitmapFromResource( res: Resources, resId: Int, reqWidth: Int, reqHeight: Int ): Bitmap { // First decode with inJustDecodeBounds=true to check dimensions return BitmapFactory.Options().run { inJustDecodeBounds = true BitmapFactory.decodeResource(res, resId, this) // Calculate inSampleSize inSampleSize = calculateInSampleSize(this, reqWidth, reqHeight) // Decode bitmap with inSampleSize set inJustDecodeBounds = false BitmapFactory.decodeResource(res, resId, this) } }
Java
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); }
Mit dieser Methode wird es einfach, eine Bitmap von beliebig großer Größe in eine ImageView
zu laden, die eine Miniaturansicht von 100 × 100 Pixel anzeigt, wie im folgenden Beispiel gezeigt.
Code:
Kotlin
imageView.setImageBitmap( decodeSampledBitmapFromResource(resources, R.id.myimage, 100, 100) )
Java
imageView.setImageBitmap( decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
Sie können ähnlich vorgehen, um Bitmaps aus anderen Quellen zu decodieren, indem Sie
Entsprechende BitmapFactory.decode*
-Methode.