在上一篇博客中我们说到,无论是LruCache与diskLruCache,都需要用key作为索引来取出图片。按照我们的思路,把图片的url传入作为key就好了。
但是这样做的话会有两个问题,第一个问题是URL包含有特殊字符,我们的key是不能包含有特殊字符的,当然你也可以自己手动指定key,图片少量还行,要是100张,1000张呢?这就会很麻烦,而且也不利于代码的维护。另一个问题就是假如我们需要隐藏URL防止别人拿到怎么办?这里就要引入MessageDigest类
用法如下
public String hashKeyFormURL(String url) {
String cacheKey;
try {
final MessageDigest mDigest = MessageDigest.getInstance("MD5");
mDigest.update(url.getBytes());
cacheKey = bytesToHexString(mDigest.digest());
} catch (NoSuchAlgorithmException e) {
cacheKey = String.valueOf(url.hashCode());
}
return cacheKey;
}
private String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(0xFF & bytes[i]);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
这是百度上面的介绍
java.security.MessageDigest类用于为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。简单点说就是用于生成散列码。信息摘要是安全的单向哈希函数,它接收任意大小的数据,输出固定长度的哈希值
我们通过MessageDigest.getInstance("MD5")获取到MessageDisgest的实例,其中MD5是算法名称,常用的算法有MD2,SHA-1,SHA-256,SHA-384,SHA-512
这里就没什么好说了,都是一些数据的处理,用的时候复制就好了
现在我们来说三级缓存中的最后一个,网络拉取功能,我们先来看看我们ImageLoader的实现逻辑
public Bitmap loadBitmap(String uri, int reqWidth, int reqHeight) {
Bitmap bitmap = loadBitmapFromMemCache(uri);
if (bitmap != null) {
Log.d(TAG, "loadBitmapFromMemCache,url:" + uri);
return bitmap;
}
try {
bitmap = loadBitmapFromDiskCache(uri, reqWidth, reqHeight);
if (bitmap != null) {
Log.d(TAG, "loadBitmapFromDisk,url:" + uri);
return bitmap;
}
bitmap = loadBitmapFromHttp(uri, reqWidth, reqHeight);
Log.d(TAG, "loadBitmapFromhttp,url:" + uri);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (bitmap == null && !mIsDiskLruCacheCreated) {
Log.w(TAG, "encounter error,DiskLruCache is not created");
bitmap = downloadBitmapFromUrl(uri);
}
return bitmap;
}
当我们loadBitmap时,我们现从LruCache(内存)里找,找不到的话再从DiskLruCache(外部存储)里找。要是都找不到的话,我们就把它从网络下载下来,存储到外部存储里,然后再从外部存储调用。万一我们没有外部存储,现在的手机好多都没有SD卡这样的配置,因为手机内存空间已经足够大了,那么我们只能从网络上下载下来,整个逻辑就是如此。我们来看看具体代码的实现loadBitmapFromHttp
private Bitmap loadBitmapFromHttp(String url, int reqWidth, int reqHeight)
throws IOException {
if (Looper.myLooper() == Looper.getMainLooper()) {
throw new RuntimeException("can not visit network from UI Thread.");
}
if (mDiskLruCache == null) {
return null;
}
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();
}
return loadBitmapFromDiskCache(url, reqWidth, reqHeight);
}
downloadUrlToStream
private boolean downloadUrlToStream(String urlString,
OutputStream outputStream) {
HttpURLConnection urlConnection = null;
BufferedOutputStream out = null;
BufferedInputStream in = null;
try {
final URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream(),
IO_BUFFER_SIZE);
out = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE);
int b;
while ((b = in.read()) != -1) {
out.write(b);
}
return true;
} catch (final IOException e) {
e.printStackTrace();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (final IOException e) {
e.printStackTrace();
}
}
return false;
}
这里就是我们网络拉取的核心代码
HttpURLConnection urlConnection = null;
BufferedOutputStream out = null;
BufferedInputStream in = null;
try {
final URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream(),
IO_BUFFER_SIZE);
out = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE);
int b;
while ((b = in.read()) != -1) {
out.write(b);
}
return true;
从网络拉取图片的BufferInputStream,把它写入到DiskLruCache的缓存文件里
private Bitmap downloadBitmapFromUrl(String urlString) {
Bitmap bitmap = null;
HttpURLConnection urlConnection = null;
BufferedInputStream in = null;
try {
final URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream(),
IO_BUFFER_SIZE);
bitmap = BitmapFactory.decodeStream(in);
} catch (final IOException e) {
Log.e(TAG, "error in downloadBitmap:" + e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return bitmap;
}
同样也是拿到bitmap,最后在imageView中imageView.setImageBitmap(bm);就可以加载图片了