实现自己的ImageLoader(3)-----网络拉取图片与key的加密

在上一篇博客中我们说到,无论是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的缓存文件里

现在我们来看一下没有SD卡时调用的downloadBitmapFromUrl

	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);就可以加载图片了





你可能感兴趣的:(Android开发)