SyncImageLoader.java中
private Map<String, SoftReference<Drawable>> imageCache = new ConcurrentHashMap<String, SoftReference<Drawable>>();
...
...
...
private void loadImage(final String mImageUrl, final Integer mt, final OnImageLoadListener mListener) {
if (imageCache.containsKey(mImageUrl)) {
SoftReference<Drawable> softReference = imageCache.get(mImageUrl);
final Drawable d = softReference.get();
if (d != null) {
handler.post(new Runnable() {
@Override
public void run() {
if (mAllowLoad) {
mListener.onImageLoad(mt, d);
}
}
});
return;
}
}
由代码可知, 获取图片时, 是先去软引用的imageCache的map中去寻找, 获取到的Drawable d 不是空的话说明获取成功,就调用回调方法mListener.onImageLoad(mt, d); 将图片显示.
如果没有在软引用中获取到图片,则执行下面的
try {
final Drawable d = loadImageFromUrl(mImageUrl);
if (d != null) {
imageCache.put(mImageUrl, new SoftReference<Drawable>(d));
}
handler.post(new Runnable() {
@Override
public void run() {
if (mAllowLoad) {
mListener.onImageLoad(mt, d);
}
}
});
} catch (IOException e) {
handler.post(new Runnable() {
@Override
public void run() {
mListener.onError(mt);
}
});
Logger.e(TAG, e);
}
这里是通过loadImageFromUrl(mImageUrl)的方法获取图片的Drawable的,然后调用回调方法mListener.onImageLoad(mt, d);显示图片, 如果出错, 则执行mListener.onError(mt);的回调方法.
(这里的mListener.onImageLoad(mt, d);mListener.onError(mt);都是需要我们程序员自定义编写的. 可以到调用loadImage的地方找到具体的回调方法)
看到这里, 我想, 把loadImageFromUrl(mImageUrl);的代码也拿过来就有必要了:
public static Drawable loadImageFromUrl(String url) throws IOException {
InputStream in = null;
OutputStream out = null;
try {
File f = new File(ECApplication.getCacheDirPath(), MD5.digest(url));
if (f.exists()) {
Logger.d(TAG, "缓存 " + f.getAbsolutePath());
return Drawable.createFromPath(f.getAbsolutePath());
}
Logger.d(TAG, "网络 " + url);
URL m = new URL(url);
in = new BufferedInputStream((InputStream) m.getContent(), BUFFER_SIZE);
out = new BufferedOutputStream(new FileOutputStream(f), BUFFER_SIZE);
byte[] buffer = new byte[BUFFER_SIZE];
int len = 0;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
} finally {
StreamUtil.Release(in, out);
}
return loadImageFromUrl(url);
}
我们会发现它先去图片缓存的文件夹中去查找图片, 如果找不到再从网上下载, 下载完后再回调自己(return loadImageFromUrl(url);),这时候File f = new File(ECApplication.getCacheDirPath(), MD5.digest(url));已经是下载的图片了. 至此, 图片缓存中有了该图片了, 那么你可能会问了, 软引用什么时候加载的该刚下载的图片呢? 我们继续看.看到 loadImage(final String mImageUrl, final Integer mt, final OnImageLoadListener mListener)中的
try {
final Drawable d = loadImageFromUrl(mImageUrl);
if (d != null) {
imageCache.put(mImageUrl, new SoftReference<Drawable>(d));
}
对的就在这里了,通过 loadImageFromUrl(String url)得到了图片信息, 不为空的话说明成功了, 则就把该图片加入了软引用中, 供以后再次使用, 因为使用了软引用保证了内存不会出现溢出的情况.
我们再看到adapter中,如: LimitbuyAdapter.java, getView的几句代码:
Drawable d = drawables[position];
if (d == null) {
view.setTag(position);
loadImage(position, list.get(position).getPic());
} else {
holderView.goodsIconIv.setBackgroundDrawable(d);
}
当图片资源并未获取到或者在获取的过程中,图片的位置会因为还没有得到图片而不显示内容. 这里没有让imageview加载一个默认的图片以提高用户体验. 我们可以根据需要在这里加上在图片未获取到时显示一张我们的默认图片的代码.
看完这些, 您可能会问final OnImageLoadListener mListener 是在哪里定义的呢? 我们看到ImageAsyncLoaderAdpter.java:
SyncImageLoader.OnImageLoadListener imageLoadListener = new SyncImageLoader.OnImageLoadListener() {
@Override
public void onImageLoad(Integer position, Drawable drawable) {
onImageLoadFinish(position, drawable);
}
@Override
public void onError(Integer t) {
onImageLoadError(t);
}
};
没错就是这里, 具体怎么实现的,可以到onImageLoadFinish(position, drawable);和onImageLoadError(t);的定义中去看了,这两个方法其实是我们自定义的,前面也有提到过.
好了. 先分析到这了.
总结:
本篇主要分析了代码中对图片做缓存和软引用的过程. 这样对图片的处理也是对涉及到图片listview的优化的很重要的一部分.
希望对大家有帮助. 谢谢.