Büyük Bit Eşlemeleri Verimli Bir Şekilde Yükleme

Not: Resim yüklemeyle ilgili en iyi uygulamaları izleyen çeşitli kitaplıklar vardır. Resimleri en optimize şekilde yüklemek için uygulamanızda bu kitaplıkları kullanabilirsiniz. Resimleri mümkün olduğunca hızlı ve sorunsuz bir şekilde yükleyip gösteren Glide kitaplığını öneririz. Diğer popüler görüntü yükleme kitaplıkları arasında Square'den Picasso, Instacart'tan Coil ve Facebook'tan Fresco yer alır. Bu kitaplıklar, Android'de bit eşlemlerle ve diğer görüntü türleriyle ilişkili karmaşık görevlerin çoğunu basitleştirir.

Resimler çeşitli şekillerde ve boyutlarda olabilir. Çoğu durumda bu boyut, tipik bir uygulama kullanıcı arayüzü için gerekenden daha büyüktür. Örneğin, sistem Galeri uygulaması Android cihazınızın kamerasıyla çekilen fotoğrafları görüntüler. Bu fotoğraflar genellikle cihazınızın ekran yoğunluğundan çok daha yüksek çözünürlüktedir.

Sınırlı bellekle çalıştığınız düşünülürse, ideal olarak yalnızca belleğe daha düşük çözünürlüklü bir sürüm yüklemek istersiniz. Düşük çözünürlüklü sürüm, onu görüntüleyen kullanıcı arayüzü bileşeninin boyutuyla eşleşmelidir. Daha yüksek çözünürlüğe sahip bir görüntü, görünür bir avantaj sağlamaz ancak yine de değerli belleği kaplar ve ölçeklemenin artması nedeniyle ek performans yüküne neden olur.

Bu derste, belleğe daha küçük bir alt örneklenmiş sürüm yükleyerek uygulama başına bellek sınırını aşmadan büyük bit eşlemlerin kodunu çözmeyi öğreneceksiniz.

Bit Eşlem Boyutlarını ve Türünü Okuma

BitmapFactory sınıfı, çeşitli kaynaklardan Bitmap oluşturmak için çeşitli kod çözme yöntemleri (decodeByteArray(), decodeFile(), decodeResource() vb.) sağlar. Görüntü veri kaynağınıza göre en uygun kod çözme yöntemini seçin. Bu yöntemler, oluşturulan bit eşlem için bellek ayırmaya çalışır ve bu nedenle kolayca OutOfMemory istisnasına yol açabilir. Her bir kod çözme yöntemi türünün, BitmapFactory.Options sınıfı aracılığıyla kod çözme seçeneklerini belirtmenize olanak tanıyan ek imzaları vardır. Kod çözerken inJustDecodeBounds özelliğinin true olarak ayarlanması, bellek ayırmanın önüne geçer. Bit eşlem nesnesi için null döndürülür ancak outWidth, outHeight ve outMimeType değerleri ayarlanır. Bu teknik, bit eşlemin oluşturulmasından (ve bellek ayrılmasından) önce resim verilerinin boyutlarını ve türünü okumanıza olanak tanır.

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;

java.lang.OutOfMemory istisnalarını önlemek için bit eşlemin kodunu çözmeden önce boyutlarını kontrol edin. Aksi halde, kaynağın mevcut belleğe rahatça sığan, tahmin edilebilir boyutta resim verileri sağlayacağına güvenmiyorsanız

Belleğe Ölçeklendirilmiş Sürüm Yükleme

Artık resim boyutları bilindiği için, tam resmin belleğe mi yükleneceğine yoksa bunun yerine alt örneklenmiş sürümün mi yükleneceğine karar vermek için kullanılabilir. Dikkate almanız gereken bazı faktörler şunlardır:

  • Bellekteki tam resmin yüklenmesi için tahmini bellek kullanımı.
  • Uygulamanızın diğer bellek gereksinimleri göz önünde bulundurulduğunda, bu resmi yüklemek için ayırmak istediğiniz bellek miktarı.
  • Resmin yükleneceği hedef ImageView veya kullanıcı arayüzü bileşeninin boyutları.
  • Mevcut cihazın ekran boyutu ve yoğunluğu.

Örneğin, 1024x768 piksel boyutundaki bir resim, ImageView boyutunda 128x96 piksel boyutunda küçük resimde görüntülenecekse belleğe yüklenmeye değmez.

Kod çözücüye, belleğe daha küçük bir sürüm yükleyerek görüntüyü alt örneklemsini bildirmek için BitmapFactory.Options nesnenizde inSampleSize değerini true olarak ayarlayın. Örneğin, çözünürlüğü 2048x1536 olan ve inSampleSize değeri 4 ile çözülen bir resim, yaklaşık 512x384 boyutunda bir bit eşlem oluşturur. Bunun belleğe yüklenmesi, tam resim için 12 MB yerine 0,75 MB kullanır (ARGB_8888 öğesinin bit eşlem yapılandırması olduğu varsayılır). Hedef genişlik ve yüksekliğe göre ikinin üssü olan örnek boyutu değerini hesaplamaya yönelik bir yöntem aşağıda verilmiştir:

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;
}

Not: İki değerin kuvveti hesaplanır çünkü kod çözücü, inSampleSize belgelerinde belirtildiği gibi, nihai değeri ikinin en yakın kuvvetine yuvarlayarak nihai değeri kullanır.

Bu yöntemi kullanmak için önce kodu inJustDecodeBounds true olarak ayarlayıp seçenekleri geçirin, ardından yeni inSampleSize değerini ve inJustDecodeBounds değerini false olarak ayarlayıp tekrar kodu çözün:

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);
}

Bu yöntem, aşağıdaki örnek kodda gösterildiği gibi, 100x100 piksel boyutunda küçük resim görüntüleyen bir ImageView öğesine rastgele büyük boyutlu bit eşlemlerin yüklenmesini kolaylaştırır:

Kotlin

imageView.setImageBitmap(
        decodeSampledBitmapFromResource(resources, R.id.myimage, 100, 100)
)

Java

imageView.setImageBitmap(
    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

Gerektiğinde uygun BitmapFactory.decode* yöntemini kullanarak diğer kaynaklardan bit eşlemlerin kodunu çözmek için benzer bir süreç izleyebilirsiniz.