到了该篇,算是Android-Universal-Image-Loader
学习的尾声阶段了吧。还没有学习前面几节的筒子们,赶快去学习一波咯。今天带你学习的是自定义Android-Universal-Image-Loader
中的缓存、图片转换,下面就进入主题,一起来学习。
图片转换:
这里还是和往常一样,先来张要实现的样子:
还没有看第三节的筒子们,赶快去看看吧面试之——Android-Universal-Image-Loader图片转换(三)
。
第三节也说了,要实现图片转换功能。其实是要自定义BitmapDisplayer
,那咋们也来看看我们如何自定义这样的BitmapDisplayer
:
public class OvalDisplayer implements BitmapDisplayer {
@Override
public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
imageAware.setImageDrawable(new OvalDrawable(bitmap));
}
static class OvalDrawable extends Drawable {
private Bitmap bitmap;
private Path ovalPath;
private Paint bitmapPaint;
public OvalDrawable(Bitmap bitmap) {
this.bitmap = bitmap;
}
@Override
public void draw(@NonNull Canvas canvas) {
int layer = canvas.saveLayer(getBounds().left, getBounds().top, getBounds().right, getBounds().bottom, null, Canvas.ALL_SAVE_FLAG);
//先绘制dst层
canvas.drawPath(ovalPath, bitmapPaint);
bitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//src层
canvas.drawBitmap(bitmap, 0, 0, bitmapPaint);
bitmapPaint.setXfermode(null);
canvas.restoreToCount(layer);
}
@Override
public void setAlpha(int alpha) {
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
//获取到宽高的缩放比例
float scaleWidth = (float) (bounds.width() * 1.0 / bitmap.getWidth());
float scaleHeight = (float) (bounds.height() * 1.0 / bitmap.getHeight());
Matrix matrix = new Matrix();
//需要对图片进行缩放
matrix.setScale(scaleWidth, scaleHeight);
//获取到缩放后的bitmap对象
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
ovalPath = new Path();
bitmapPaint = new Paint();
//添加dst层的椭圆
ovalPath.addOval(bounds.left, bounds.top, bounds.right, bounds.bottom, Path.Direction.CCW);
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
}
看到没有,这里其实是自定义一个Drawable
,这里画椭圆的方式我是按照paint.setXfermode的方式来绘制。但是在画之前肯定是要对图片进行缩放,该操作在onBoundsChange
中初始化,紧接着添加dst层的path,因此在绘制的时候,会留下两层的src交集,因此大家看到的就是一个椭圆的图片了。
然后在使用的时候:
- 代码传送门:
ImageLoaderListActivity
缓存:
前面第二张已经分析过了LruMemoryCache
的缓存策略是优先移除最不经常使用的bitmap,这里我就稍作一点更改,将使用次数作为衡量要不要移除bitmap,马上LimitCountMemoryCache
也能登场了:
public class LimitCountMemoryCache implements MemoryCache {
//定义一个存储所有bitmap使用次数的map
private final Map<Bitmap, Integer> limitCountMap = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());
//限制使用次数由用户决定
public LimitCountMemoryCache(int limitCount) {
this.limitCount = limitCount;
this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);
}
private int limitCount;
private final LinkedHashMap<String, Bitmap> map;
@Override
public final Bitmap get(String key) {
if (key == null) {
throw new NullPointerException("key == null");
}
synchronized (this) {
Bitmap current = map.get(key);
if (current != null) {
//如果存在当前的bitmap将次数加1
if (limitCountMap.get(current) != null) {
Integer count = limitCountMap.get(current);
limitCountMap.put(current, count++);
} else {
//如果不存在说明还是第一次使用,因此只是初始化次数=1
limitCountMap.put(current, 1);
}
//这里判断使用的次数了,如果大于limitCount,则需要移除该对象了
if (limitCountMap.get(current) > limitCount) {
map.remove(current);
limitCountMap.remove(current);
}
}
return current;
}
}
/**
* Caches {@code Bitmap} for {@code key}. The Bitmap is moved to the head of the queue.
*/
@Override
public final boolean put(String key, Bitmap value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
}
synchronized (this) {
map.put(key, value);
}
return true;
}
@Override
public final Bitmap remove(String key) {
if (key == null) {
throw new NullPointerException("key == null");
}
synchronized (this) {
Bitmap previous = map.remove(key);
return previous;
}
}
@Override
public Collection<String> keys() {
synchronized (this) {
return new HashSet<String>(map.keySet());
}
}
@Override
public void clear() {
map.clear();
limitCountMap.clear();
}
}
大家主要是看get方法,用了一个limitCountMap
存储bitmap的使用次数,如果是第一次使用,那次数肯定=1;否则就加1。所以在移除bitmap的时候去判断是否大于limitCount,是不是逻辑很简单呢。
在使用的地方加上这么一句:
由于这里涉及到缓存部分,无法看效果图。所以请大家自行看代码理解。
- 代码传送门
LimitCountMemoryCache
好了,关于自定义缓存、图片转换就介绍到这里,如果有什么问题,请加群讨论184793647