Android官方开发文档Training系列课程中文版:高效显示位图之管理位图内存
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Android官方开发文档Training系列课程中文版:高效显示位图之管理位图内存,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6857字,纯文字阅读大概需要10分钟。
内容图文
原文地址:http://developer.android.com/training/displaying-bitmaps/manage-memory.html
除了在上一节中描述的步骤之外,还有一些细节上的事情可以促进垃圾回收器的回收及位图的复用。其推荐的策略取决于Android的目标版本。示例APP BitmapFun展示了如何使应用程序在不同的版本上高效的工作。
为了给这节课的知识奠定一些基础,下面有一些Android系统如何管理位图内存的一些改进需要了解:
- 在Android 2.2之前,当垃圾回收器回收时,应用的线程会被停止。这会降低性能发生延迟。Android 2.3增加了并发收集垃圾的功能,这意味着内存回收不久之后位图不可再被引用。
- 在Android 2.3.3之前,位图对应的支撑数据被存放在本地内存中。这与位图本身是分离的,它被存储在Dalvik堆栈之中。在意料之中位于本地内存中的像素数据是不会被释放的,可能会导致程序超过自身的内存限制然后崩溃。从在Android 3.0开始,像素数据与之相关的位图被一同存入了Dalvik虚拟机堆栈内。
下面的部分会介绍如何对不同的安卓版本进行位图内存的优化与管理。
在Android 2.3之前的版本上管理内存
在2.3之前推荐使用recycle()方法。如果你在APP内展示了大量的位图数据,那么你很有可能会遇到OutOfMemoryError错误。recycle()方法允许应用尽可能的回收内存。
Caution: 你应该在确保位图不再使用的时候使用recycle()方法。如果你调用了recycle()方法之后去尝试绘制这个位图,你将会得到错误:”Canvas: trying to use a recycled bitmap”。
下面的代码是recycle()方法的示例用法。它使用了引用计数的方式来追踪位图当前是处于被展示状态还是被缓存状态。当处于以下状况时,代码会回收位图:
- 引用数mDisplayRefCount及 mCacheRefCount都是0。
- 位图不为null,并且还没有被回收。
private
int mCacheRefCount = 0;
privateint mDisplayRefCount = 0;
...
// Notify the drawable that the displayed state has changed.// Keep a count to determine when the drawable is no longer displayed.publicvoidsetIsDisplayed(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.publicvoidsetIsCached(boolean isCached) {
synchronized (this) {
if (isCached) {
mCacheRefCount++;
} else {
mCacheRefCount--;
}
}
// Check to see if recycle() can be called.
checkState();
}
privatesynchronizedvoidcheckState() {
// 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();
}
}
privatesynchronizedbooleanhasValidBitmap() {
Bitmap bitmap = getBitmap();
return bitmap != null && !bitmap.isRecycled();
}
在Android 3.0之后的版本上管理内存
Android 3.0中介绍了BitmapFactory.Options.inBitmap属性。如果设置了这个选项,那么解码方法会尝试去重用一个已经存在的位图。这也就是说位图的内存是可重用的,这可以促使改善性能,并且不需要再申请内存及释放内存。然而,inBitmap如何使用还有一些限制,在Android 4.4之前,仅支持相同大小的位图。更多信息,请看文档:inBitmap。
保存位图以便稍后使用
下面的代码演示了如何存储一个位图以便稍后使用。当APP运行在Android 3.0以上时,位图会被LruCache移除,接着一个引用位图的软性引用会被放置到一个HashSet中,以便稍后可能被用到:
Set<SoftReference<Bitmap>> mReusableBitmaps;
private LruCache<String, BitmapDrawable> mMemoryCache;
// If you‘re running on Honeycomb or newer, create a// synchronized HashSet of references to reusable bitmaps.if (Utils.hasHoneycomb()) {
mReusableBitmaps =
Collections.synchronizedSet(new HashSet<SoftReference<Bitmap>>());
}
mMemoryCache = new LruCache<String, BitmapDrawable>(mCacheParams.memCacheSize) {
// Notify the removed entry that is no longer being cached.@OverrideprotectedvoidentryRemoved(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()));
}
}
}
....
}
使用已经存在的位图
在运行中的APP内,解码方法会检查是否有已经存在的位图可以被再次使用:
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);
}
addInBitmapOptions():
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()) {
synchronized (mReusableBitmaps) {
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;
}
最后,这里方法会检查候选位图是否满足大小:
static
boolean canUseForInBitmap(
Bitmap candidate, BitmapFactory.Options targetOptions) {
if (Build.VERSION.SDK_INT >= 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 <= candidate.getAllocationByteCount();
}
// On earlier versions, the dimensions must match exactly and the inSampleSize must be 1return 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.
*/staticint getBytesPerPixel(Config config) {
if (config == Config.ARGB_8888) {
return4;
} elseif (config == Config.RGB_565) {
return2;
} elseif (config == Config.ARGB_4444) {
return2;
} elseif (config == Config.ALPHA_8) {
return1;
}
return1;
}
下面片段所展示的方法会被上面的片段所调用。它会寻找存在的位图然后将其设置为值。注意这个方法只是对适合的匹配对象设置值。
原文:http://blog.csdn.net/sahadev_/article/details/51378762
内容总结
以上是互联网集市为您收集整理的Android官方开发文档Training系列课程中文版:高效显示位图之管理位图内存全部内容,希望文章能够帮你解决Android官方开发文档Training系列课程中文版:高效显示位图之管理位图内存所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。