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

* commit '7fd5c53c4507995da1e1f1300a2f9def30bffce8':
  Displaying Bitmaps Efficiently Training - updates for KitKat inBitmap changes Bug: 10411797
This commit is contained in:
Adam Koch
2013-10-28 17:18:28 -07:00
committed by Android Git Automerger
4 changed files with 53 additions and 38 deletions

View File

@@ -188,8 +188,8 @@ appropriate place to store cached images if they are accessed more frequently, f
image gallery application.</p> image gallery application.</p>
<p>The sample code of this class uses a {@code DiskLruCache} implementation that is pulled from the <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>. Heres updated example code that adds a disk cache in addition <a href="https://android.googlesource.com/platform/libcore/+/jb-mr2-release/luni/src/main/java/libcore/io/DiskLruCache.java">Android source</a>.
to the existing memory cache:</p> Heres updated example code that adds a disk cache in addition to the existing memory cache:</p>
<pre> <pre>
private DiskLruCache mDiskLruCache; private DiskLruCache mDiskLruCache;

View File

@@ -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 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 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}). Heres image (assuming a bitmap configuration of {@link android.graphics.Bitmap.Config ARGB_8888}). Heres
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> <pre>
public static int calculateInSampleSize( public static int calculateInSampleSize(
@@ -107,26 +108,26 @@ public static int calculateInSampleSize(
final int width = options.outWidth; final int width = options.outWidth;
int inSampleSize = 1; 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 halfHeight = height / 2;
final int heightRatio = Math.round((float) height / (float) reqHeight); final int halfWidth = width / 2;
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee // Calculate the largest inSampleSize value that is a power of 2 and keeps both
// a final image with both dimensions larger than or equal to the // height and width larger than the requested height and width.
// requested height and width. while ((halfHeight / inSampleSize) &gt; reqHeight
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; && (halfWidth / inSampleSize) &gt; reqWidth) {
inSampleSize *= 2;
}
} }
return inSampleSize; return inSampleSize;
} }
</pre> </pre>
<p class="note"><strong>Note:</strong> Using powers of 2 for {@link <p class="note"><strong>Note:</strong> A power of two value is calculated because the decoder uses
android.graphics.BitmapFactory.Options#inSampleSize} values is faster and more efficient for the a final value by rounding down to the nearest power of two, as per the {@link
decoder. However, if you plan to cache the resized versions in memory or on disk, its usually still android.graphics.BitmapFactory.Options#inSampleSize} documentation.</p>
worth decoding to the most appropriate image dimensions to save space.</p>
<p>To use this method, first decode with {@link <p>To use this method, first decode with {@link
android.graphics.BitmapFactory.Options#inJustDecodeBounds} set to {@code true}, pass the options android.graphics.BitmapFactory.Options#inJustDecodeBounds} set to {@code true}, pass the options

View File

@@ -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 which is stored in the Dalvik heap. The pixel data in native memory is
not released in a predictable manner, potentially causing an application not released in a predictable manner, potentially causing an application
to briefly exceed its memory limits and crash. 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> Dalvik heap along with the associated bitmap.</strong></li>
</ul> </ul>
@@ -140,27 +140,16 @@ private synchronized boolean hasValidBitmap() {
<h2 id="inBitmap">Manage Memory on Android 3.0 and Higher</h2> <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} {@link android.graphics.BitmapFactory.Options#inBitmap BitmapFactory.Options.inBitmap}
field. If this option is set, decode methods that take the field. If this option is set, decode methods that take the
{@link android.graphics.BitmapFactory.Options Options} object {@link android.graphics.BitmapFactory.Options Options} object
will attempt to reuse an existing bitmap when loading content. This means will attempt to reuse an existing bitmap when loading content. This means
that the bitmap's memory is reused, resulting in improved performance, and 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 removing both memory allocation and de-allocation. However, there are certain restrictions with how
{@link android.graphics.BitmapFactory.Options#inBitmap}:</p> {@link android.graphics.BitmapFactory.Options#inBitmap} can be used. In particular, before Android
<ul> 4.4 (API level 19), only equal sized bitmaps are supported. For details, please see the
<li>The reused bitmap must be of the same size as the source content (to make {@link android.graphics.BitmapFactory.Options#inBitmap} documentation.
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>
<h3>Save a bitmap for later use</h3> <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 satisfies the size criteria to be used for
{@link android.graphics.BitmapFactory.Options#inBitmap}:</p> {@link android.graphics.BitmapFactory.Options#inBitmap}:</p>
<pre>private static boolean canUseForInBitmap( <pre>static boolean canUseForInBitmap(
Bitmap candidate, BitmapFactory.Options targetOptions) { Bitmap candidate, BitmapFactory.Options targetOptions) {
int width = targetOptions.outWidth / targetOptions.inSampleSize;
int height = targetOptions.outHeight / targetOptions.inSampleSize;
// Returns true if "candidate" can be used for inBitmap re-use with if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.KITKAT) {
// "targetOptions". // From Android 4.4 (KitKat) onward we can re-use if the byte size of
return candidate.getWidth() == width && candidate.getHeight() == height; // 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();
}
// 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> }</pre>
</body> </body>