当前位置:   article > 正文

管理Bitmap的存储空间_bitmap 内存在本地吗?

bitmap 内存在本地吗?

注:1.在Android2.2(API level 8)之前,当垃圾回收线程工作时,主线程会阻塞,这就造成了不好的用户体验,

所以在以后的版本中,出现了并发执行的垃圾回收线程,这意味着当一个Bitmap没有被引用时,就会被回收;

2.在Android2.3.3(API level 10)之前,Bitmap的像素数据是存储在本地内存中,且与Bitmap本身是分开存储的,

(Bitmap存储在Dalvik虚拟机的堆内存中)。在Android3.0(API level 11)版本之后,两者都存储在虚拟机堆内存中。

一、管理Android2.3.3之前版本设备的Bitmap存储

建议使用recycle()方法回收空间,应该在Bitmap对象不再被使用了调用该方法。如果已经recycle后尝试使用该Bitmap,

会得到如下错误: "Canvas: trying to use a recycled bitmap".

  1. private int mCacheRefCount = 0;
  2. private int mDisplayRefCount = 0;
  3. ...
  4. // Notify the drawable that the displayed state has changed.
  5. // Keep a count to determine when the drawable is no longer displayed.
  6. public void setIsDisplayed(boolean isDisplayed) {
  7. synchronized (this) {
  8. if (isDisplayed) {
  9. mDisplayRefCount++;
  10. mHasBeenDisplayed = true;
  11. } else {
  12. mDisplayRefCount--;
  13. }
  14. }
  15. // Check to see if recycle() can be called.
  16. checkState();
  17. }
  18. // Notify the drawable that the cache state has changed.
  19. // Keep a count to determine when the drawable is no longer being cached.
  20. public void setIsCached(boolean isCached) {
  21. synchronized (this) {
  22. if (isCached) {
  23. mCacheRefCount++;
  24. } else {
  25. mCacheRefCount--;
  26. }
  27. }
  28. // Check to see if recycle() can be called.
  29. checkState();
  30. }
  31. private synchronized void checkState() {
  32. // If the drawable cache and display ref counts = 0, and this drawable
  33. // has been displayed, then recycle.
  34. if (mCacheRefCount <= 0 && mDisplayRefCount <= 0 && mHasBeenDisplayed
  35. && hasValidBitmap()) {
  36. getBitmap().recycle();
  37. }
  38. }
  39. private synchronized boolean hasValidBitmap() {
  40. Bitmap bitmap = getBitmap();
  41. return bitmap != null && !bitmap.isRecycled();
  42. }

二、在Android3.0版本之后的设备上管理Bitmap存储空间

Android3.0版本介绍了 BitmapFactory.Options.inBitmap字段,如果给该字段赋值,则在解码时会尝试

使用这个已存在的Bitmap对象,这意味着该Bitmap的存储空间被重复利用了。但是在Android4.4(API level 19)

之前,只有尺寸一样的Bitmap才能被复用。

1.保存不再缓存的Bitmap引用

  1. Set<SoftReference<Bitmap>> mReusableBitmaps;
  2. private LruCache<String, BitmapDrawable> mMemoryCache;
  3. // If you're running on Honeycomb or newer, create a
  4. // synchronized HashSet of references to reusable bitmaps.
  5. if (Utils.hasHoneycomb()) {
  6. mReusableBitmaps =
  7. Collections.synchronizedSet(new HashSet<SoftReference<Bitmap>>());
  8. }
  9. mMemoryCache = new LruCache<String, BitmapDrawable>(mCacheParams.memCacheSize) {
  10. // Notify the removed entry that is no longer being cached.
  11. @Override
  12. protected void entryRemoved(boolean evicted, String key,
  13. BitmapDrawable oldValue, BitmapDrawable newValue) {
  14. if (RecyclingBitmapDrawable.class.isInstance(oldValue)) {
  15. // The removed entry is a recycling drawable, so notify it
  16. // that it has been removed from the memory cache.
  17. ((RecyclingBitmapDrawable) oldValue).setIsCached(false);
  18. } else {
  19. // The removed entry is a standard BitmapDrawable.
  20. if (Utils.hasHoneycomb()) {
  21. // We're running on Honeycomb or later, so add the bitmap
  22. // to a SoftReference set for possible use with inBitmap later.
  23. mReusableBitmaps.add
  24. (new SoftReference<Bitmap>(oldValue.getBitmap()));
  25. }
  26. }
  27. }
  28. ....
  29. }

2.尝试使用已经存在的Bitmap对象:

  1. public static Bitmap decodeSampledBitmapFromFile(String filename,
  2. int reqWidth, int reqHeight, ImageCache cache) {
  3. final BitmapFactory.Options options = new BitmapFactory.Options();
  4. ...
  5. BitmapFactory.decodeFile(filename, options);
  6. ...
  7. // If we're running on Honeycomb or newer, try to use inBitmap.
  8. if (Utils.hasHoneycomb()) {
  9. addInBitmapOptions(options, cache);
  10. }
  11. ...
  12. return BitmapFactory.decodeFile(filename, options);
  13. }

3.给option添加inBitmap属性值:

  1. private static void addInBitmapOptions(BitmapFactory.Options options,
  2. ImageCache cache) {
  3. // inBitmap only works with mutable bitmaps, so force the decoder to
  4. // return mutable bitmaps.
  5. options.inMutable = true;
  6. if (cache != null) {
  7. // Try to find a bitmap to use for inBitmap.
  8. Bitmap inBitmap = cache.getBitmapFromReusableSet(options);
  9. if (inBitmap != null) {
  10. // If a suitable bitmap has been found, set it as the value of
  11. // inBitmap.
  12. options.inBitmap = inBitmap;
  13. }
  14. }
  15. }

4.从保存的Bitmap引用中寻找合适的Bitmap对象:

  1. // This method iterates through the reusable bitmaps, looking for one
  2. // to use for inBitmap:
  3. protected Bitmap getBitmapFromReusableSet(BitmapFactory.Options options) {
  4. Bitmap bitmap = null;
  5. if (mReusableBitmaps != null && !mReusableBitmaps.isEmpty()) {
  6. synchronized (mReusableBitmaps) {
  7. final Iterator<SoftReference<Bitmap>> iterator
  8. = mReusableBitmaps.iterator();
  9. Bitmap item;
  10. while (iterator.hasNext()) {
  11. item = iterator.next().get();
  12. if (null != item && item.isMutable()) {
  13. // Check to see it the item can be used for inBitmap.
  14. if (canUseForInBitmap(item, options)) {
  15. bitmap = item;
  16. // Remove from reusable set so it can't be used again.
  17. iterator.remove();
  18. break;
  19. }
  20. } else {
  21. // Remove from the set if the reference has been cleared.
  22. iterator.remove();
  23. }
  24. }
  25. }
  26. }
  27. return bitmap;
  28. }
5.判断当前Bitmap是否可用:

  1. static boolean canUseForInBitmap(
  2. Bitmap candidate, BitmapFactory.Options targetOptions) {
  3. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  4. // From Android 4.4 (KitKat) onward we can re-use if the byte size of
  5. // the new bitmap is smaller than the reusable bitmap candidate
  6. // allocation byte count.
  7. int width = targetOptions.outWidth / targetOptions.inSampleSize;
  8. int height = targetOptions.outHeight / targetOptions.inSampleSize;
  9. int byteCount = width * height * getBytesPerPixel(candidate.getConfig());
  10. return byteCount <= candidate.getAllocationByteCount();
  11. }
  12. // On earlier versions, the dimensions must match exactly and the inSampleSize must be 1
  13. return candidate.getWidth() == targetOptions.outWidth
  14. && candidate.getHeight() == targetOptions.outHeight
  15. && targetOptions.inSampleSize == 1;
  16. }
  17. /**
  18. * A helper function to return the byte usage per pixel of a bitmap based on its configuration.
  19. */
  20. static int getBytesPerPixel(Config config) {
  21. if (config == Config.ARGB_8888) {
  22. return 4;
  23. } else if (config == Config.RGB_565) {
  24. return 2;
  25. } else if (config == Config.ARGB_4444) {
  26. return 2;
  27. } else if (config == Config.ALPHA_8) {
  28. return 1;
  29. }
  30. return 1;
  31. }





声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/303726
推荐阅读
相关标签
  

闽ICP备14008679号