Android图片的拉取与缓存

Anroid应用中经常会有从网上拉取图片的需求,拉图片说简单也很好做,说难也是很费力的,虽然网上的方案很多,开源框架也不少,但具体的实现还是得看需求。下面分享一下我在项目中用到的两种拉图片方案。

1. 少量图片

如果图片少量,使用框架就显得冗余,直接下载就更简洁一些。

(String url, String savePath) {LogUtil.v(TAG, “url=” + url + “; savepath=” + savePath);if (TextUtils.isEmpty(url) || TextUtils.isEmpty(savePath)) {return false;}// 初始化下载路径,删除已存在的文件以及生成目录String tempPath = savePath + “_temp”;checkFilePath(savePath);checkFilePath(tempPath);// 拉取资源,具体实现网上很多HttpEntity entity = getHttpEntity(url);if (entity == null) {return false;}// 检查剩余空间long imgLength = entity.getContentLength();long spaceLeft = SdCardSize.getUsableSpace(savePath);LogUtil.v(TAG, “space left =” + spaceLeft);if (imgLength <= 0 || spaceLeft < imgLength*3) {LogUtil.v(TAG, “imgLength*3=” + imgLength*3);return false;}try {InputStream stream = entity.getContent();LogUtil.i(TAG, “imgLength = ” + imgLength);(imgLength == writeImageFile(stream, tempPath)&& FileUtil.renameFile(tempPath, savePath)) {return true;} else {LogUtil.w(TAG, “failed to write image file”);FileUtil.deleteFile(tempPath);}} catch (IllegalStateException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return false;}

此方法仅仅是下载图片,返回是否下载成功,这个功能应该需求不多,因为只是下载了图片,并没有返回bitmap对象,便于直接使用。如果需要直接使用图片的话在拿到inputstream时就可以直接用BitmapFactory.decodeStream(is)得到bitmap对象;

2. 大量图片

对于需要拉取大量图片的需求,上面的方法不是很好用,主要是线程的封装,以及优先级,还有缓存的处理。在这里根据需求修改volley来实现。

(final String url, final String savePath, int width, int height,final IFetchDataListener<Bitmap> listener) {ImageRequest request = new ImageRequest(url, new Listener<Bitmap>() {(Bitmap response) {LogUtil.v(TAG, “fetchImage ByteCount=” + response.getByteCount());// 返回拉取的bitmaplistener.onFetchFinished(response);}}, width, height, ScaleType.FIT_XY, Config.ARGB_8888, new ErrorListener() {(VolleyError error) {LogUtil.e(TAG, “fetchImage url=” + url);LogUtil.e(TAG, “fetchImage error=” + error);// volley拉取失败后,再采用第一种方法拉取一遍ThreadManager.getPoolProxy().execute(new Runnable() {() {final Bitmap bitmap = ImageFetcher.getImage(url, savePath);LogUtil.v(TAG, “bitmap from imagefetcher:” + bitmap);// 将拉取的结果返回给UI线程new InnerHandle().post(new Runnable() {() {listener.onFetchFinished(bitmap);}});}});}});mQueue.add(request);}

之所以使用volley,是因为volley对于request以及消息的管理机制很不错,自己实现的很难完善,所以就直接采用volley。在volley拉取失败后又用土办法重新拉一遍是因为实际情况如此,volley拉取时一直都是返回404错误,但是此时土方法每次都能拉取成功,就把两者结合起来了。

public static Bitmap getImage(String url, String savePath) {LogUtil.v(TAG, “url=” + url + “;savePath=” + savePath);if (TextUtils.isEmpty(savePath)) {return null;}// 从本地文件读取图片Bitmap bitmap = getImageByPath(savePath);if (bitmap != null) {return bitmap;}// 从网络拉取if (downloadImage(url, savePath)) {return getImageByPath(savePath);}return null;}

修改volley磁盘缓存方案 volley在将缓存写入磁盘时会将数据附带的信息也写入同一个文件,这样导致我们并不能直接使用volley在磁盘缓存的文件,根据我最开始的方法可以看出,我是需要直接使用图片文件。所以修改了volley的磁盘缓存DiskBasedCache。

(String key, Entry entry) {pruneIfNeeded(entry.data.length);File file = getFileForKey(key);try {FileOutputStream fos = new FileOutputStream(file);CacheHeader e = new CacheHeader(key, entry);fos.write(entry.data);fos.close();putEntry(key, e);return;} catch (IOException e) {}boolean deleted = file.delete();if (!deleted) {VolleyLog.d(“Could not clean up file %s”, file.getAbsolutePath());}}

同样的,还需要修改get方法,不然volley自己就用不了缓存文件了。

public synchronized Entry get(String key) {CacheHeader entry = mEntries.get(key);// if the entry does not exist, return.if (entry == null) {return null;}VolleyLog.v(“getEntry key=” + key);File file = getFileForKey(key);CountingInputStream cis = null;try {cis = new CountingInputStream(new BufferedInputStream(new FileInputStream(file)));[] data = streamToBytes(cis, (int) file.length());return entry.toCacheEntry(data);} catch (IOException e) {VolleyLog.d(“%s: %s”, file.getAbsolutePath(), e.toString());remove(key);return null;} catch (NegativeArraySizeException e) {VolleyLog.d(“%s: %s”, file.getAbsolutePath(), e.toString());remove(key);return null;} finally {if (cis != null) {try {cis.close();} catch (IOException ioe) {return null;}}}}每个人的生命都是可以绽放美丽,只要你珍惜。

Android图片的拉取与缓存

相关文章:

你感兴趣的文章:

标签云: