美文网首页
Android位图

Android位图

作者: 竹叶儿青 | 来源:发表于2020-06-07 17:16 被阅读0次

处理位图:
https://developer.android.com/topic/performance/graphics

高效加载:
https://developer.android.com/topic/performance/graphics/load-bitmap

缓存位图:
https://developer.android.com/topic/performance/graphics/cache-bitmap

郭霖写的:
https://blog.csdn.net/guolin_blog/article/details/9316683

1. 加载位图

两个关键参数:

/** * If set to true, the decoder will return null (no bitmap), but * the 
<code>out...</code> fields will still be set, allowing the caller to * query 
the bitmap without having to allocate the memory for its pixels. */
// 设置为true,则解码器不会为bitmap分配内存,而仅仅是为outHeight和outWight等设置值。
 public boolean inJustDecodeBounds;

/** * If set to a value > 1, requests the decoder to subsample the original * 
image, returning a smaller image to save memory. The sample size is * 
the number of pixels in either dimension that correspond to a single * 
pixel in the decoded bitmap. For example, inSampleSize == 4 returns * 
an image that is 1/4 the width/height of the original, and 1/16 the * 
number of pixels. Any value <= 1 is treated the same as 1\. Note: the * 
decoder uses a final value based on powers of 2, any other value will * 
be rounded down to the nearest power of 2.*/
 // 下采样的参数。大于1,则会对宽高除以这个值,用于节省内存; 小于1则默认为1。 并且这个值需要是2的幂次,否则会向下取整。
public int inSampleSize;

加载图片确定是加载完整图片还是下采样的图片,需要考虑以下因素:

  1. 可分配给图片的内存

  2. 加载完整的图片需要的内存

  3. 当前设备的屏幕大小和密度

  4. 展示图片的ImageView或其他控件的尺寸

代码:

public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {

final int imageWidth = options.outWidth;

    final int imageHeight = options.outHeight;

    int inSampleSize =1;

    if (imageWidth > reqWidth || imageHeight > reqHeight) {

final int halfWidth = imageWidth /2;

        final int halfHeight = imageHeight /2;

        while ((halfHeight / inSampleSize) > reqHeight

&& (halfWidth / inSampleSize) > reqWidth) {

inSampleSize *=2;

        }

}

return inSampleSize;

}

public BitmapdecodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {

BitmapFactory.Options options =new BitmapFactory.Options();

    // set to true to check dimensions

    options.inJustDecodeBounds =true;

    BitmapFactory.decodeResource(res, resId, options);

    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // decode bitmap

    options.inJustDecodeBounds =false;

    return BitmapFactory.decodeResource(getResources(), R.drawable.error, options);

}

具体使用:

imageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.drawable.error, 100, 100));

2. 缓存位图

如果只是对Bitmap进行加载的优化,在仅展示少量图片的情况下足够了,但是如果是在RecyclerView等控件中使用,就需要对图片进行缓存,一方面能够快速流畅的加载页面,提高页面响应速度,一方面节省带宽,避免了每展示一次就重新请求一次、处理一次。

缓存分为内存缓存和磁盘缓存,内存缓存速度快,容量小,磁盘缓存容量大,速度慢。

内存缓存

使用LruCache实现,使用LinkedHashMap保存bitmap,并在超出限定容量前移除最近最久未使用的资源(可以将其放入磁盘缓存)。

为LruCache设置缓存大小,需要考虑以下因素:

  1. 设备可以为应用程序分配多少内存;

  2. 屏幕上一次会展示多少图片,有多少图片要准备好用于展示;

  3. 设备的屏幕大小和分辨率;

  4. 位图的尺寸和大小,也即每个图片需要占据的内存大小;

  5. 图片被访问的频率,如果有些图片的访问频率比其他的高,可以将其设置为常驻内存,或者设置多个LruCache来区分图片;

  6. 图片质量和数量之间的平衡,有时候大量的低质量的图片更好,不过这样就需要后台另开线程去加载高清大图。

代码:


private LruCachememoryCache;

public void initMemoryCache() {

// get max available memory and stored in Kb

    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() /1024);

    final int cacheSize = maxMemory /8;

    memoryCache =new LruCache(cacheSize) {

@Override

        protected int sizeOf(String key, Bitmap value) {

return value.getByteCount() /1024;

        }

};

}

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {

if (getBitmapFromMemoryCache(key) ==null) {

memoryCache.put(key, bitmap);

    }

}

public BitmapgetBitmapFromMemoryCache(String key) {

if (memoryCache ==null) {

initMemoryCache();

    }

return memoryCache.get(key);

}

实际使用


public void loadBitmap(int resId) {

final String key = String.valueOf(resId);

    final Bitmap bitmap = getBitmapFromMemoryCache(key);

    if (bitmap !=null) {

mImageView.setImageBitmap(bitmap);

    }else {

mImageView.setImageResource(R.drawable.error);

        mImageView.setImageBitmap(loadBitmapFromInternet(resId));

    }

}

public BitmaploadBitmapFromInternet(int resId) {

final Bitmap bitmap = decodeSampledBitmapFromResource(getResources(), resId, 100, 100);

    addBitmapToMemoryCache(String.valueOf(resId), bitmap);

    return bitmap;

}

磁盘缓存

需要在后台线程读取缓存的bitmap,可以缓存处理过的图片和未处理的图片,如Glide的DiskCacheStrategy.RESOURCE和DiskCacheStrategy.DATA,当从内存中找不到缓存时,就从磁盘中查找,如果磁盘中既没有处理后的图片,也没有原始的未处理的图片,那就从网上加载,然后将原始数据和处理后的数据存入磁盘,将处理后的资源存入内存。

相关文章

网友评论

      本文标题:Android位图

      本文链接:https://www.haomeiwen.com/subject/niwttktx.html