Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 45895d74 authored by Adam Koch's avatar Adam Koch Committed by Android Git Automerger
Browse files

am 7fd5c53c: Merge "Displaying Bitmaps Efficiently Training - updates for...

am 7fd5c53c: Merge "Displaying Bitmaps Efficiently Training - updates for KitKat inBitmap changes Bug: 10411797" into klp-dev

* commit '7fd5c53c':
  Displaying Bitmaps Efficiently Training - updates for KitKat inBitmap changes Bug: 10411797
parents c7f18b52 7fd5c53c
Loading
Loading
Loading
Loading
−326 KiB (101 KiB)

File changed.

No diff preview for this file type.

+2 −2
Original line number Diff line number Diff line
@@ -188,8 +188,8 @@ appropriate place to store cached images if they are accessed more frequently, f
image gallery application.</p>

<p>The sample code of this class uses a {@code DiskLruCache} implementation that is pulled from the 
<a href="https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/libcore/io/DiskLruCache.java">Android source</a>. Here’s updated example code that adds a disk cache in addition
to the existing memory cache:</p>
<a href="https://android.googlesource.com/platform/libcore/+/jb-mr2-release/luni/src/main/java/libcore/io/DiskLruCache.java">Android source</a>.
Here’s updated example code that adds a disk cache in addition to the existing memory cache:</p>

<pre>
private DiskLruCache mDiskLruCache;
+14 −13
Original line number Diff line number Diff line
@@ -97,7 +97,8 @@ android.graphics.BitmapFactory.Options} object. For example, an image with resol
is decoded with an {@link android.graphics.BitmapFactory.Options#inSampleSize} of 4 produces a
bitmap of approximately 512x384. Loading this into memory uses 0.75MB rather than 12MB for the full
image (assuming a bitmap configuration of {@link android.graphics.Bitmap.Config ARGB_8888}). Here’s
a method to calculate a the sample size value based on a target width and height:</p>
a method to calculate a sample size value that is a power of two based on a target width and
height:</p>

<pre>
public static int calculateInSampleSize(
@@ -107,26 +108,26 @@ public static int calculateInSampleSize(
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {
    if (height &gt; reqHeight || width &gt; reqWidth) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);
        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        // 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) &gt; reqHeight
                && (halfWidth / inSampleSize) &gt; reqWidth) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}
</pre>

<p class="note"><strong>Note:</strong> Using powers of 2 for {@link
android.graphics.BitmapFactory.Options#inSampleSize} values is faster and more efficient for the
decoder. However, if you plan to cache the resized versions in memory or on disk, it’s usually still
worth decoding to the most appropriate image dimensions to save space.</p>
<p class="note"><strong>Note:</strong> A power of two value is calculated because the decoder uses
a final value by rounding down to the nearest power of two, as per the {@link
android.graphics.BitmapFactory.Options#inSampleSize} documentation.</p>

<p>To use this method, first decode with {@link
android.graphics.BitmapFactory.Options#inJustDecodeBounds} set to {@code true}, pass the options
+37 −23
Original line number Diff line number Diff line
@@ -56,7 +56,7 @@ bitmap is stored in native memory. It is separate from the bitmap itself,
which is stored in the Dalvik heap. The pixel data in native memory is
not released in a predictable manner, potentially causing an application
to briefly exceed its memory limits and crash.
<strong>As of Android 3.0 (API Level 11), the pixel data is stored on the
<strong>As of Android 3.0 (API level 11), the pixel data is stored on the
Dalvik heap along with the associated bitmap.</strong></li>

</ul>
@@ -140,27 +140,16 @@ private synchronized boolean hasValidBitmap() {

<h2 id="inBitmap">Manage Memory on Android 3.0 and Higher</h2>

<p>Android 3.0 (API Level 11) introduces the
<p>Android 3.0 (API level 11) introduces the
{@link android.graphics.BitmapFactory.Options#inBitmap BitmapFactory.Options.inBitmap}
field. If this option is set, decode methods that take the 
{@link android.graphics.BitmapFactory.Options Options} object
will attempt to reuse an existing bitmap when loading content. This means
that the bitmap's memory is reused, resulting in improved performance, and
removing both memory allocation and de-allocation. There are some caveats in using
{@link android.graphics.BitmapFactory.Options#inBitmap}:</p>
<ul>
  <li>The reused bitmap must be of the same size as the source content (to make
sure that the same amount of memory is used), and in JPEG or PNG format
(whether as a resource or as a stream).</li>


<li>The {@link android.graphics.Bitmap.Config configuration} of the reused bitmap
overrides the setting of
{@link android.graphics.BitmapFactory.Options#inPreferredConfig}, if set. </li>

  <li>You should always use the returned bitmap of the decode method,
because you can't assume that reusing the bitmap worked (for example, if there is
a size mismatch).</li>
removing both memory allocation and de-allocation. However, there are certain restrictions with how
{@link android.graphics.BitmapFactory.Options#inBitmap} can be used. In particular, before Android
4.4 (API level 19), only equal sized bitmaps are supported. For details, please see the
{@link android.graphics.BitmapFactory.Options#inBitmap} documentation.

<h3>Save a bitmap for later use</h3>

@@ -283,14 +272,39 @@ protected Bitmap getBitmapFromReusableSet(BitmapFactory.Options options) {
satisfies the size criteria to be used for
{@link android.graphics.BitmapFactory.Options#inBitmap}:</p>

<pre>private static boolean canUseForInBitmap(
<pre>static boolean canUseForInBitmap(
        Bitmap candidate, BitmapFactory.Options targetOptions) {

    if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.KITKAT) {
        // From Android 4.4 (KitKat) onward we can re-use if the byte size of
        // the new bitmap is smaller than the reusable bitmap candidate
        // allocation byte count.
        int width = targetOptions.outWidth / targetOptions.inSampleSize;
        int height = targetOptions.outHeight / targetOptions.inSampleSize;
        int byteCount = width * height * getBytesPerPixel(candidate.getConfig());
        return byteCount &lt;= candidate.getAllocationByteCount();
    }

    // Returns true if "candidate" can be used for inBitmap re-use with
    // "targetOptions".
    return candidate.getWidth() == width && candidate.getHeight() == height;
    // On earlier versions, the dimensions must match exactly and the inSampleSize must be 1
    return candidate.getWidth() == targetOptions.outWidth
            && candidate.getHeight() == targetOptions.outHeight
            && targetOptions.inSampleSize == 1;
}

/**
 * A helper function to return the byte usage per pixel of a bitmap based on its configuration.
 */
static int getBytesPerPixel(Config config) {
    if (config == Config.ARGB_8888) {
        return 4;
    } else if (config == Config.RGB_565) {
        return 2;
    } else if (config == Config.ARGB_4444) {
        return 2;
    } else if (config == Config.ALPHA_8) {
        return 1;
    }
    return 1;
}</pre>

</body>