1.Bitmap的高效加载
BitmapFactory类提供了四类方法:decodeFile,decodeResource,decodeStream和decodeByteArray,分别用于支持从文件系统,资源,输入流以及字节数组中加载出一个Bitmap对象,其中decodeFile和decodeResource又间接调用了decodeStream方法,这四类方法最终是在Android的底层实现的。
BitmapFactory.Options用来对图片进行采样缩放。
inSampleSize参数,即采样率,取值n应该总是2的指数(1,2,4,8…),采样后图片的宽/高均为原图大小的1/n。
inJustDecodeBounds参数,设置为true时,BitmapFactory只会解析图片的原始宽/高信息,并不会去真正地加载图片,所以这个操作是轻量级的。需要注意的是,这个时候BitmapFactory获取的图片宽高信息和图片的位置以及程序运行的设备有关,这都可能导致BitmapFactory获取到不同的结果。
获取采样率:
public static Bitmap decodeBmpFromRes(Resources res, int resId, int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int width = options.outWidth;
final int height = options.outHeight;
int inSampleSize = 1;
if (width > reqWidth || height > reqHeight) {
final int halfWidth = width / 2;
final int halfHeight = height / 2;
while ((halfWidth / inSampleSize) >= reqWidth && (halfWidth / inSampleSize) >= reqHeight) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
mImageView.setImageBitmap(decodeBmpFromRes(getResource(), R.id.myimage, 100, 100));
2.Android中的缓存策略
LRU(Least Recently Used),近期最少使用算法,其核心思想是当缓存满时,会优先淘汰那些近期最少使用的缓存对象。
1.LruCache-内存缓存
LruCache是一个线程安全的泛型类,它内部采用一个LinkedHashMap以强引用的方式存储外界的缓存对象,其提供了get和put方法来完成缓存的获取和添加操作,当缓存满时,LruCache会移除较早使用的缓存对象,然后再添加新的缓存对象。
强引用:直接的对象引用。
软引用:当一个对象只有软引用存在时,系统内存不足时此对象会被gc回收。
弱引用:当一个对象只有弱引用存在时,次对象会随时被gc回收。
LruCache初始化:
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
}
}
从LruCache中获取一个缓存对象:
mMemoryCache.get(key);
向LruCache中添加一个缓存对象:
mMemoryCache.put(key, bitmap);
2.DiskLruCache-存储设备缓存
1.DiskLruCache的创建
DiskLruCache并不能通过构造方法来创建,它提供了open方法用于创建自身,如下:
// derectory:表示磁盘缓存在文件系统中的存储路径。
// appVersion:表示应用的版本号,一般设为1即可。
// valueCount:表示单个节点所对应的数据的个数,一般设为1即可。
// maxSize:表示缓存的总大小。
public static DiskLruCache open(File derectory, int appVersion, int valueCount, long maxSize);
典型DiskLruCache创建过程:
private static final long DISK_CACHE_SIZE = 1024 * 1024 * 50; //50M
File diskCacheDir = getDiskCacheDir(mContext, "bitmap");
if (!diskCacheDir.exists()) {
diskCacheDir.mkdirs();
}
mDiskLruCache = DiskLruCache.open(diskCacheDir, 1, 1, DISK_CACHE_SIZE);
2.DiskLruCache的缓存添加
DiskLruCache的缓存添加的操作是通过Editor完成的,Editor表示一个缓存对象的编辑对象。
private static final int DISK_CACHE_INDEX = 0; // valueCount的个数为1,index为0
String key = hashKeyFormUrl(url);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
if (editor != null) {
OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);
if (downloadUrlToStream(url, outputStream)) {
editor.commit();
} else {
editor.abort();
}
mDiskLruCache.flush();
}
3.DiskLruCache的缓存查找
通过DiskLruCache的get方法得到一个Snapshot对象,通过Snapshot对象可得到缓存的文件输入流。
Bitmap bitmap = null;
String key = hashKeyFormUrl(url);
DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);
if (snapShot != null) {
FileInputStream fileInputStream = (FileInputStream) snapShot.getInputStream(DISK_CACHE_INDEX);
FileDescriptor fileDescriptor = fileInputStream.getFD();
bitmap = mImageResizer.decodeBmpFromFD(fileDescriptor, reqWidth, reqHeight);
if (bitmap != null) {
addBitmapToMemoryCache(key, bitmap);
}
}
3.ImageLoader的实现
功能:图片的同步/异步加载,图片压缩,内存缓存,磁盘缓存,网络拉取。
ImageLoader.java
3.ImageLoader的使用
1.图片墙效果
2.优化列表的卡顿现象
1.不要在getView中执行耗时操作,不直接在getView中加载图片,应采用异步方式处理。
2.控制异步任务的执行频率:在列表滑动的时候停止加载图片,等列表停下来以后再加载图片。
3.在某些特殊情况下,开启硬件加速:给Activity添加配置android:hardwareAccelerated=”true”。