处理位图:
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;
加载图片确定是加载完整图片还是下采样的图片,需要考虑以下因素:
-
可分配给图片的内存
-
加载完整的图片需要的内存
-
当前设备的屏幕大小和密度
-
展示图片的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设置缓存大小,需要考虑以下因素:
-
设备可以为应用程序分配多少内存;
-
屏幕上一次会展示多少图片,有多少图片要准备好用于展示;
-
设备的屏幕大小和分辨率;
-
位图的尺寸和大小,也即每个图片需要占据的内存大小;
-
图片被访问的频率,如果有些图片的访问频率比其他的高,可以将其设置为常驻内存,或者设置多个LruCache来区分图片;
-
图片质量和数量之间的平衡,有时候大量的低质量的图片更好,不过这样就需要后台另开线程去加载高清大图。
代码:
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,当从内存中找不到缓存时,就从磁盘中查找,如果磁盘中既没有处理后的图片,也没有原始的未处理的图片,那就从网上加载,然后将原始数据和处理后的数据存入磁盘,将处理后的资源存入内存。
网友评论