Android 自己来尝试性解读《Android照片墙完整版,完美结合LruCache和DiskLruCache》
来源:互联网 发布:利用网络赚钱的方法 编辑:程序博客网 时间:2024/04/28 01:55
基于主管建议我看下缓存这方面的资料,所以找到了郭神的《Android照片墙完整版,完美结合LruCache和DiskLruCache》
http://blog.csdn.net/guolin_blog/article/details/34093441
和《Android DiskLruCache完全解析,硬盘缓存的最佳方案》
http://blog.csdn.net/guolin_blog/article/details/28863651
很荣幸能了解到大神对缓存的理解。所以特地把我对前篇代码阅读的心得体会记录下来,若有哪里说得不好、说错的,欢迎指正,至于后一篇大神已经说得非常非常好了,我也没啥说的。
public class PhotoWallAdapter extends ArrayAdapter<String>public PhotoWallAdapter(Context context, int resource, String[] objects, GridView photoWall) { super(context, resource, objects); taskCollection = new HashSet<BitmapWorkerTask>(); mOkHttpClient = new OkHttpClient(); mPhotoWall = photoWall; //获取应用程序最大的可用内存 int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheSize = maxMemory / 8; //设置图片缓存大小为最大可用内存的1/8 mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap value) { return value.getByteCount(); } }; //获取图片缓存路径 File cacheDir = getDiskCacheDir(context, "pzh"); if (!cacheDir.exists()) { cacheDir.mkdirs(); } try { //设置10M的磁盘缓存 mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, 10 * 1024 * 1024); } catch (IOException e) { e.printStackTrace(); } }
可以看到郭神,是自己定义了一个适配器,这个适配器中,需要传入上下文、Url和GridView。原文中是用HttpUrlConnection,与时俱进,我就用OkHttp来代替。因为这是结合内存缓存和磁盘缓存来使用,所以思路是:先从内存里根据Key获取,若没有则从磁盘缓存里获取,还没有就下载,然后放进内存缓存(若有空间,没有就放磁盘缓存),接着再呈现出来。所以构造方法里步骤如下:
1、先获取获取程序最大运行内存Runtime.getRuntime().maxMemory(),再分配其中的八分之一给图片缓存new LruCache
@Override public View getView(int position, View convertView, ViewGroup parent) { //这里的数据是之前构造方法String[] objects里得到的 String url = getItem(position); View view; if (convertView != null) { view = convertView; } else { view = View.inflate(getContext(), R.layout.photo_layout, null); } ImageView imageView = (ImageView) view.findViewById(R.id.photo); //设置item的高度 if (imageView.getLayoutParams().height != mItemHeight) { imageView.getLayoutParams().height = mItemHeight; } //给Imageview设置,避免异步加载时图片不会乱序 imageView.setTag(url); imageView.setImageResource(R.mipmap.ic_launcher); loadBitmaps(imageView, url); return view; }
这里主要是想看loadBitmaps(imageView, url);
private void loadBitmaps(ImageView imageView, String url) { Bitmap bitmap = getBitmapFromMemoryCache(url); if (bitmap == null) { BitmapWorkerTask task = new BitmapWorkerTask(); taskCollection.add(task); task.execute(url); } else { if (imageView != null && bitmap != null) { imageView.setImageBitmap(bitmap); } } }
1、首先getBitmapFromMemoryCache(url)从缓存中得到图片
2、若图片为空,则new BitmapWorkerTask()新建一个异步加载任务, taskCollection.add(task);同时把这个任务记录在HashSet中,以便可以取消这个加载任务。
3、若缓存中有图片,就直接显示出来
接下来看看如何从缓存中的到图片
private Bitmap getBitmapFromMemoryCache(String url) { return mMemoryCache.get(url); }
很简单,根据key来可以获取。当然第一次加载为空,没什么可说的,那么就需要看看如何异步加载图片,放进缓存的操作
class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> { private String imageUrl; @Override protected Bitmap doInBackground(String... params) { //这个url是task.execute(url);这里传进来的,只传进来一个数,所以是params数组里的第0位 imageUrl = params[0]; FileDescriptor fileDescriptor = null; FileInputStream fileInputStream = null; DiskLruCache.Snapshot snapshot = null; //生成Url对应Md5加密的key String key = hashKeyForDisk(imageUrl); try { snapshot = mDiskLruCache.get(key); if (snapshot == null) { //如果找不到对应的缓存,则从网络上下载,并写入缓存中 DiskLruCache.Editor editor = mDiskLruCache.edit(key); if (editor != null) { OutputStream outputStream = editor.newOutputStream(0); if (downLoadUrlToStream(imageUrl, outputStream)) { editor.commit(); }else{ editor.abort(); } } snapshot = mDiskLruCache.get(key); } if(snapshot != null){ fileInputStream = (FileInputStream) snapshot.getInputStream(0); fileDescriptor = fileInputStream.getFD(); } //将数据解析成bitmap对象 Bitmap bitmap = null; if(fileDescriptor != null){ bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor); } if(bitmap != null){ addBitmapToMemoryCache(params[0],bitmap); } return bitmap; } catch (IOException e) { e.printStackTrace(); }finally { if (fileInputStream != null) { try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); ImageView imageView = (ImageView) mPhotoWall.findViewWithTag(imageUrl); if(imageView != null && bitmap != null){ imageView.setImageBitmap(bitmap); } taskCollection.remove(this); } }
1、内存缓存没有图片,下载前先读取磁盘,就用Snapshot 这个类来读取磁盘缓存,若不为空,那么snapshot.getInputStream(0)可以读取到输入流,接着转成Bitmap,addBitmapToMemoryCache(params[0],bitmap)把url作为key和Bitmap放进缓存里面,当然key是url有些不规范,可以md5加密
2、若磁盘没有图片,就只能下载了,downLoadUrlToStream(imageUrl, outputStream)
private boolean downLoadUrlToStream(String imageUrl, final OutputStream outputStream) { Request request = new Request.Builder() .url(imageUrl) .build(); Call call = mOkHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { } @Override public void onResponse(Response response) throws IOException { InputStream is = null; BufferedOutputStream out = null; BufferedInputStream in = null; try { is = response.body().byteStream(); in = new BufferedInputStream(is, 8 * 1024); out = new BufferedOutputStream(outputStream, 8 * 1024); int b; while ((b = in.read()) != -1) { out.write(b); } isSuccess = true; } catch (IOException e) { e.printStackTrace(); } finally { if (is != null) { is.close(); } if (in != null) { in.close(); } if(out != null){ out.close(); } } } }); return isSuccess; }
使用OkHttp,需要定义Request和Call参数,response.body().byteStream()得到下载的输入流,把它写进输出流即可
这样就可以 editor.commit();就可以生成磁盘的缓存文件了, editor.abort();若下载不成功就废弃掉
最后加上两个方法
public void fluchCache(){ if(mDiskLruCache != null){ try { mDiskLruCache.flush(); } catch (IOException e) { e.printStackTrace(); } } }
将缓存记录同步到journal文件中。
public void cancelAllTasks(){ if(taskCollection != null){ for(BitmapWorkerTask task : taskCollection){ task.cancel(false); } } }
取消所有下载任务
- Android 自己来尝试性解读《Android照片墙完整版,完美结合LruCache和DiskLruCache》
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- 【android】照片墙完整版,完美结合LruCache和DiskLruCache
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- Awesome Python
- java list与Json转换
- Awesome PHP
- JAVA设计模式之单例模式
- Awesome Hadoop
- Android 自己来尝试性解读《Android照片墙完整版,完美结合LruCache和DiskLruCache》
- ExtJS Grid组件实现分页功能
- C++ STL算法
- Move Zeroes
- 23种设计模式汇总整理
- 给volley封装访问的header头信息,利用头信息区分和校验用户权限
- 有淡入效果3D效果的scrollView
- Json 与 JsonNode 转换
- Introduction to Scientific Programing and Simulation Using R chapter 04 答案