am 96a60639
: am eb46c95c
: am 4758e3e7
: Merge "Doc update: Add memory mgt lesson to bitmaps class" into jb-mr1.1-docs
* commit '96a6063943d725c9febc2bc525cb8be648c34fa5': Doc update: Add memory mgt lesson to bitmaps class
This commit is contained in:
Binary file not shown.
@ -3,10 +3,6 @@ parent.title=Displaying Bitmaps Efficiently
|
|||||||
parent.link=index.html
|
parent.link=index.html
|
||||||
|
|
||||||
trainingnavtop=true
|
trainingnavtop=true
|
||||||
next.title=Displaying Bitmaps in Your UI
|
|
||||||
next.link=display-bitmap.html
|
|
||||||
previous.title=Processing Bitmaps Off the UI Thread
|
|
||||||
previous.link=process-bitmap.html
|
|
||||||
|
|
||||||
@jd:body
|
@jd:body
|
||||||
|
|
||||||
|
@ -3,8 +3,6 @@ parent.title=Displaying Bitmaps Efficiently
|
|||||||
parent.link=index.html
|
parent.link=index.html
|
||||||
|
|
||||||
trainingnavtop=true
|
trainingnavtop=true
|
||||||
previous.title=Caching Bitmaps
|
|
||||||
previous.link=cache-bitmap.html
|
|
||||||
|
|
||||||
@jd:body
|
@jd:body
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ next.link=load-bitmap.html
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>This class covers some common techniques for processing and loading {@link
|
<p>Learn how to use common techniques to process and load {@link
|
||||||
android.graphics.Bitmap} objects in a way that keeps your user interface (UI) components responsive
|
android.graphics.Bitmap} objects in a way that keeps your user interface (UI) components responsive
|
||||||
and avoids exceeding your application memory limit. If you're not careful, bitmaps can quickly
|
and avoids exceeding your application memory limit. If you're not careful, bitmaps can quickly
|
||||||
consume your available memory budget leading to an application crash due to the dreaded
|
consume your available memory budget leading to an application crash due to the dreaded
|
||||||
@ -70,6 +70,9 @@ exception:<br />{@code java.lang.OutofMemoryError: bitmap size exceeds VM budget
|
|||||||
<dd>This lesson walks you through using a memory and disk bitmap cache to improve the
|
<dd>This lesson walks you through using a memory and disk bitmap cache to improve the
|
||||||
responsiveness and fluidity of your UI when loading multiple bitmaps.</dd>
|
responsiveness and fluidity of your UI when loading multiple bitmaps.</dd>
|
||||||
|
|
||||||
|
<dt><b><a href="manage-memory.html">Managing Bitmap Memory</a></b></dt>
|
||||||
|
<dd>This lesson explains how to manage bitmap memory to maximize your app's performance.</dd>
|
||||||
|
|
||||||
<dt><b><a href="display-bitmap.html">Displaying Bitmaps in Your UI</a></b></dt>
|
<dt><b><a href="display-bitmap.html">Displaying Bitmaps in Your UI</a></b></dt>
|
||||||
<dd>This lesson brings everything together, showing you how to load multiple bitmaps into
|
<dd>This lesson brings everything together, showing you how to load multiple bitmaps into
|
||||||
components like {@link android.support.v4.view.ViewPager} and {@link android.widget.GridView}
|
components like {@link android.support.v4.view.ViewPager} and {@link android.widget.GridView}
|
||||||
|
@ -3,8 +3,6 @@ parent.title=Displaying Bitmaps Efficiently
|
|||||||
parent.link=index.html
|
parent.link=index.html
|
||||||
|
|
||||||
trainingnavtop=true
|
trainingnavtop=true
|
||||||
next.title=Processing Bitmaps Off the UI Thread
|
|
||||||
next.link=process-bitmap.html
|
|
||||||
|
|
||||||
@jd:body
|
@jd:body
|
||||||
|
|
||||||
|
297
docs/html/training/displaying-bitmaps/manage-memory.jd
Normal file
297
docs/html/training/displaying-bitmaps/manage-memory.jd
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
page.title=Managing Bitmap Memory
|
||||||
|
parent.title=Displaying Bitmaps Efficiently
|
||||||
|
parent.link=index.html
|
||||||
|
|
||||||
|
trainingnavtop=true
|
||||||
|
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
<div id="tb-wrapper">
|
||||||
|
<div id="tb">
|
||||||
|
|
||||||
|
<h2>This lesson teaches you to</h2>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#recycle">Manage Memory on Android 2.3.3 and Lower</a></li>
|
||||||
|
<li><a href="#inBitmap">Manage Memory on Android 3.0 and Higher</a></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h2>You should also read</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html">Memory Analysis for Android Applications</a> blog post</li>
|
||||||
|
<li><a href="http://www.google.com/events/io/2011/sessions/memory-management-for-android-apps.html">Memory management for Android Apps</a> Google I/O presentation</li>
|
||||||
|
<li><a href="{@docRoot}design/patterns/swipe-views.html">Android Design: Swipe Views</a></li>
|
||||||
|
<li><a href="{@docRoot}design/building-blocks/grid-lists.html">Android Design: Grid Lists</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Try it out</h2>
|
||||||
|
|
||||||
|
<div class="download-box">
|
||||||
|
<a href="{@docRoot}shareables/training/BitmapFun.zip" class="button">Download the sample</a>
|
||||||
|
<p class="filename">BitmapFun.zip</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>In addition to the steps described in <a href="cache-bitmap.html">Caching Bitmaps</a>,
|
||||||
|
there are specific things you can do to facilitate garbage collection
|
||||||
|
and bitmap reuse. The recommended strategy depends on which version(s)
|
||||||
|
of Android you are targeting. The {@code BitmapFun} sample app included with
|
||||||
|
this class shows you how to design your app to work efficiently across
|
||||||
|
different versions of Android.</p>
|
||||||
|
|
||||||
|
<p>To set the stage for this lesson, here is how Android's management of
|
||||||
|
bitmap memory has evolved:</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
On Android Android 2.2 (API level 8) and lower, when garbage
|
||||||
|
collection occurs, your app's threads get stopped. This causes a lag that
|
||||||
|
can degrade performance.
|
||||||
|
<strong>Android 2.3 adds concurrent garbage collection, which means that
|
||||||
|
the memory is reclaimed soon after a bitmap is no longer referenced.</strong>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>On Android 2.3.3 (API level 10) and lower, the backing pixel data for a
|
||||||
|
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
|
||||||
|
Dalvik heap along with the associated bitmap.</strong></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>The following sections describe how to optimize bitmap memory
|
||||||
|
management for different Android versions.</p>
|
||||||
|
|
||||||
|
<h2 id="recycle">Manage Memory on Android 2.3.3 and Lower</h2>
|
||||||
|
|
||||||
|
<p>On Android 2.3.3 (API level 10) and lower, using
|
||||||
|
{@link android.graphics.Bitmap#recycle recycle()}
|
||||||
|
is recommended. If you're displaying large amounts of bitmap data in your app,
|
||||||
|
you're likely to run into
|
||||||
|
{@link java.lang.OutOfMemoryError} errors. The
|
||||||
|
{@link android.graphics.Bitmap#recycle recycle()} method allows an app
|
||||||
|
to reclaim memory as soon as possible.</p>
|
||||||
|
|
||||||
|
<p class="note"><strong>Caution:</strong> You should use
|
||||||
|
{@link android.graphics.Bitmap#recycle recycle()} only when you are sure that the
|
||||||
|
bitmap is no longer being used. If you call {@link android.graphics.Bitmap#recycle recycle()}
|
||||||
|
and later attempt to draw the bitmap, you will get the error:
|
||||||
|
{@code "Canvas: trying to use a recycled bitmap"}.</p>
|
||||||
|
|
||||||
|
<p>The following code snippet gives an example of calling
|
||||||
|
{@link android.graphics.Bitmap#recycle recycle()}. It uses reference counting
|
||||||
|
(in the variables {@code mDisplayRefCount} and {@code mCacheRefCount}) to track
|
||||||
|
whether a bitmap is currently being displayed or in the cache. The
|
||||||
|
code recycles the bitmap when these conditions are met:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>The reference count for both {@code mDisplayRefCount} and
|
||||||
|
{@code mCacheRefCount} is 0.</li>
|
||||||
|
<li>The bitmap is not {@code null}, and it hasn't been recycled yet.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<pre>private int mCacheRefCount = 0;
|
||||||
|
private int mDisplayRefCount = 0;
|
||||||
|
...
|
||||||
|
// Notify the drawable that the displayed state has changed.
|
||||||
|
// Keep a count to determine when the drawable is no longer displayed.
|
||||||
|
public void setIsDisplayed(boolean isDisplayed) {
|
||||||
|
synchronized (this) {
|
||||||
|
if (isDisplayed) {
|
||||||
|
mDisplayRefCount++;
|
||||||
|
mHasBeenDisplayed = true;
|
||||||
|
} else {
|
||||||
|
mDisplayRefCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check to see if recycle() can be called.
|
||||||
|
checkState();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify the drawable that the cache state has changed.
|
||||||
|
// Keep a count to determine when the drawable is no longer being cached.
|
||||||
|
public void setIsCached(boolean isCached) {
|
||||||
|
synchronized (this) {
|
||||||
|
if (isCached) {
|
||||||
|
mCacheRefCount++;
|
||||||
|
} else {
|
||||||
|
mCacheRefCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check to see if recycle() can be called.
|
||||||
|
checkState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void checkState() {
|
||||||
|
// If the drawable cache and display ref counts = 0, and this drawable
|
||||||
|
// has been displayed, then recycle.
|
||||||
|
if (mCacheRefCount <= 0 && mDisplayRefCount <= 0 && mHasBeenDisplayed
|
||||||
|
&& hasValidBitmap()) {
|
||||||
|
getBitmap().recycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized boolean hasValidBitmap() {
|
||||||
|
Bitmap bitmap = getBitmap();
|
||||||
|
return bitmap != null && !bitmap.isRecycled();
|
||||||
|
}</pre>
|
||||||
|
|
||||||
|
<h2 id="inBitmap">Manage Memory on Android 3.0 and Higher</h2>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<h3>Save a bitmap for later use</h3>
|
||||||
|
|
||||||
|
<p>The following snippet demonstrates how an existing bitmap is stored for possible
|
||||||
|
later use in the sample app. When an app is running on Android 3.0 or higher and
|
||||||
|
a bitmap is evicted from the {@link android.util.LruCache},
|
||||||
|
a soft reference to the bitmap is placed
|
||||||
|
in a {@link java.util.HashSet}, for possible reuse later with
|
||||||
|
{@link android.graphics.BitmapFactory.Options#inBitmap}:
|
||||||
|
|
||||||
|
<pre>HashSet<SoftReference<Bitmap>> mReusableBitmaps;
|
||||||
|
private LruCache<String, BitmapDrawable> mMemoryCache;
|
||||||
|
|
||||||
|
// If you're running on Honeycomb or newer, create
|
||||||
|
// a HashSet of references to reusable bitmaps.
|
||||||
|
if (Utils.hasHoneycomb()) {
|
||||||
|
mReusableBitmaps = new HashSet<SoftReference<Bitmap>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
mMemoryCache = new LruCache<String, BitmapDrawable>(mCacheParams.memCacheSize) {
|
||||||
|
|
||||||
|
// Notify the removed entry that is no longer being cached.
|
||||||
|
@Override
|
||||||
|
protected void entryRemoved(boolean evicted, String key,
|
||||||
|
BitmapDrawable oldValue, BitmapDrawable newValue) {
|
||||||
|
if (RecyclingBitmapDrawable.class.isInstance(oldValue)) {
|
||||||
|
// The removed entry is a recycling drawable, so notify it
|
||||||
|
// that it has been removed from the memory cache.
|
||||||
|
((RecyclingBitmapDrawable) oldValue).setIsCached(false);
|
||||||
|
} else {
|
||||||
|
// The removed entry is a standard BitmapDrawable.
|
||||||
|
if (Utils.hasHoneycomb()) {
|
||||||
|
// We're running on Honeycomb or later, so add the bitmap
|
||||||
|
// to a SoftReference set for possible use with inBitmap later.
|
||||||
|
mReusableBitmaps.add
|
||||||
|
(new SoftReference<Bitmap>(oldValue.getBitmap()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
....
|
||||||
|
}</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Use an existing bitmap</h3>
|
||||||
|
<p>In the running app, decoder methods check to see if there is an existing
|
||||||
|
bitmap they can use. For example:</p>
|
||||||
|
|
||||||
|
<pre>public static Bitmap decodeSampledBitmapFromFile(String filename,
|
||||||
|
int reqWidth, int reqHeight, ImageCache cache) {
|
||||||
|
|
||||||
|
final BitmapFactory.Options options = new BitmapFactory.Options();
|
||||||
|
...
|
||||||
|
BitmapFactory.decodeFile(filename, options);
|
||||||
|
...
|
||||||
|
|
||||||
|
// If we're running on Honeycomb or newer, try to use inBitmap.
|
||||||
|
if (Utils.hasHoneycomb()) {
|
||||||
|
addInBitmapOptions(options, cache);
|
||||||
|
}
|
||||||
|
...
|
||||||
|
return BitmapFactory.decodeFile(filename, options);
|
||||||
|
}</pre
|
||||||
|
|
||||||
|
<p>The next snippet shows the {@code addInBitmapOptions()} method that is called in the
|
||||||
|
above snippet. It looks for an existing bitmap to set as the value for
|
||||||
|
{@link android.graphics.BitmapFactory.Options#inBitmap}. Note that this
|
||||||
|
method only sets a value for {@link android.graphics.BitmapFactory.Options#inBitmap}
|
||||||
|
if it finds a suitable match (your code should never assume that a match will be found):</p>
|
||||||
|
|
||||||
|
<pre>private static void addInBitmapOptions(BitmapFactory.Options options,
|
||||||
|
ImageCache cache) {
|
||||||
|
// inBitmap only works with mutable bitmaps, so force the decoder to
|
||||||
|
// return mutable bitmaps.
|
||||||
|
options.inMutable = true;
|
||||||
|
|
||||||
|
if (cache != null) {
|
||||||
|
// Try to find a bitmap to use for inBitmap.
|
||||||
|
Bitmap inBitmap = cache.getBitmapFromReusableSet(options);
|
||||||
|
|
||||||
|
if (inBitmap != null) {
|
||||||
|
// If a suitable bitmap has been found, set it as the value of
|
||||||
|
// inBitmap.
|
||||||
|
options.inBitmap = inBitmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method iterates through the reusable bitmaps, looking for one
|
||||||
|
// to use for inBitmap:
|
||||||
|
protected Bitmap getBitmapFromReusableSet(BitmapFactory.Options options) {
|
||||||
|
Bitmap bitmap = null;
|
||||||
|
|
||||||
|
if (mReusableBitmaps != null && !mReusableBitmaps.isEmpty()) {
|
||||||
|
final Iterator<SoftReference<Bitmap>> iterator
|
||||||
|
= mReusableBitmaps.iterator();
|
||||||
|
Bitmap item;
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
item = iterator.next().get();
|
||||||
|
|
||||||
|
if (null != item && item.isMutable()) {
|
||||||
|
// Check to see it the item can be used for inBitmap.
|
||||||
|
if (canUseForInBitmap(item, options)) {
|
||||||
|
bitmap = item;
|
||||||
|
|
||||||
|
// Remove from reusable set so it can't be used again.
|
||||||
|
iterator.remove();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Remove from the set if the reference has been cleared.
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bitmap;
|
||||||
|
}</pre>
|
||||||
|
|
||||||
|
<p>Finally, this method determines whether a candidate bitmap
|
||||||
|
satisfies the size criteria to be used for
|
||||||
|
{@link android.graphics.BitmapFactory.Options#inBitmap}:</p>
|
||||||
|
|
||||||
|
<pre>private static boolean canUseForInBitmap(
|
||||||
|
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
|
||||||
|
// "targetOptions".
|
||||||
|
return candidate.getWidth() == width && candidate.getHeight() == height;
|
||||||
|
}</pre>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -3,10 +3,6 @@ parent.title=Displaying Bitmaps Efficiently
|
|||||||
parent.link=index.html
|
parent.link=index.html
|
||||||
|
|
||||||
trainingnavtop=true
|
trainingnavtop=true
|
||||||
next.title=Caching Bitmaps
|
|
||||||
next.link=cache-bitmap.html
|
|
||||||
previous.title=Loading Large Bitmaps Efficiently
|
|
||||||
previous.link=load-bitmap.html
|
|
||||||
|
|
||||||
@jd:body
|
@jd:body
|
||||||
|
|
||||||
|
@ -287,6 +287,10 @@
|
|||||||
Caching Bitmaps
|
Caching Bitmaps
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li><a href="<?cs var:toroot ?>training/displaying-bitmaps/manage-memory.html">
|
||||||
|
Managing Bitmap Memory
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li><a href="<?cs var:toroot ?>training/displaying-bitmaps/display-bitmap.html">
|
<li><a href="<?cs var:toroot ?>training/displaying-bitmaps/display-bitmap.html">
|
||||||
Displaying Bitmaps in Your UI
|
Displaying Bitmaps in Your UI
|
||||||
</a></li>
|
</a></li>
|
||||||
|
Reference in New Issue
Block a user