Thinking in Google Doc-图片框架的实现及布局优化
学习谷歌文档,总结如下: 1.图片加载框架的封装 1)利用HttpURLConnection来封装网络加载图片的方法 2)创建自定义的AsyncTask来封装1)中加载网络图片的方法,并显示到控件上。 3)暴露方法封装2)中自定义的加载并显示图片的AsyncTask 走完上面这几步,只需调用一个方法,就可以从网络上加载一张图片并且显示到控件上了。 解决List并发下载图片错位的问题 但是,谷歌文档中说上面代码会存在一个问题。就是如果在List里使用,复用的话,可能会发生图 图片错位的问题:就是某个item显示的图片,可能显示的图片是之前的item的图片。因为之前的这 张图片可能加载时间比较长,滑动后imageview是复用的,所以后面的item可能会显示之前的item的 图片。 这种就是由于并发产生的问题,谷歌工程师是这么解决问题的: 1》定义一个类 class DownloadedDrawable extends ColorDrawable,然后将下载的异步任务 DownloadAsyncTask与其绑定起来。 1 2 3 4 5 6 7 8 9 10 11 12 13 public static void display(Contextcontext,Stringurl,ImageViewimageView){ BitmapbitmapFromMemCache=LruCacheUtil.getBitmapFromMemCache(url); if (bitmapFromMemCache!= null ){ imageView.setImageBitmap(bitmapFromMemCache); } else { if (cancelPotentialDownload(url,imageView)){ BitmapDownloaderTasktask= new BitmapDownloaderTask(context,imageView); DownloadedDrawabledownloadedDrawable= new DownloadedDrawable(task); imageView.setImageDrawable(downloadedDrawable); task.execute(url); } } } 2》定义2个方法 BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) --得到与ImageView绑定的异步下载任务 1 2 3 4 5 6 7 8 9 10 public static BitmapDownloaderTaskgetBitmapDownloaderTask(ImageViewimageView){ if (imageView!= null ){ Drawabledrawable=imageView.getDrawable(); if (drawable instanceof DownloadedDrawable){ DownloadedDrawabledownloadedDrawable=(DownloadedDrawable)drawable; return downloadedDrawable.getBitmapDownloaderTask(); } } return null ; } boolean cancelPotentialDownload(String url, ImageView imageView) --取消可能正在进行的下载,并返回是否已经取消。 如果与imageView绑定的下载任务不为空,再判断与ImageView绑定的异步下载任务的URL,如果 为null或者是与当前方法传递进来URL不一致,说明异步下载任务正在执行之前的下载,就取消任 务,否则说明任务正在执行中且url一致,就不重新开启任务。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 private static boolean cancelPotentialDownload(Stringurl,ImageViewimageView){ BitmapDownloaderTaskbitmapDownloaderTask=BitmapDownloaderTask.getBitmapDownloaderTask(imageView); if (bitmapDownloaderTask!= null ){ StringbitmapUrl=bitmapDownloaderTask.url; if ((bitmapUrl== null )||(!bitmapUrl.equals(url))){ bitmapDownloaderTask.cancel( true ); } else { //ThesameURLisalreadybeingdownloaded. return false ; } } return true ; } 解决图片缓存的问题 1》用内存来缓存,使用LruCache这个类。 内存的特点: 内存加载速度比较快,但是内存在开关机之后会被回收,缓存的数据会消失。 底层: LinkedHashMap来实现存储 实现原理: 当从url下载图片之前,先判断缓存中存不存在图片,如果存在直接加载图片,不存在则 去网络请求图片。 当AsyncTask下载完图片之后,如果不为null,就存放到缓存中。 于是我写了个工具类LruCacheUtils来完成图片的缓存 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class LruCacheUtil{ //LruCacheforbitmap private static LruCache<String,Bitmap>mMemoryCache; static { //GetmaxavailableVMmemory,exceedingthisamountwillthrowan //OutOfMemoryexception.StoredinkilobytesasLruCachetakesan //intinitsconstructor. final int maxMemory=( int )(Runtime.getRuntime().maxMemory()/ 1024 ); //Use1/8thoftheavailablememoryforthismemorycache. final int cacheSize=maxMemory/ 8 ; mMemoryCache= new LruCache<String,Bitmap>(cacheSize){ @TargetApi (Build.VERSION_CODES.HONEYCOMB_MR1) @Override protected int sizeOf(Stringkey,Bitmapbitmap){ //Thecachesizewillbemeasuredinkilobytesratherthan //numberofitems. return bitmap.getByteCount()/ 1024 ; } }; } public static void addBitmapToMemoryCache(Stringkey,Bitmapbitmap){ if (getBitmapFromMemCache(key)== null ){ mMemoryCache.put(key,bitmap); } } public static BitmapgetBitmapFromMemCache(Stringkey){ return mMemoryCache.get(key); } } 2》使用磁盘(Disk)来缓存,使用DiskLruCache(这个类google文档里并没有提供) Android DiskLruCache 源码解析 硬盘缓存的绝佳方案 http://blog.csdn.net/lmj623565791/article/details/47251585 下载链接 http://http://www.oschina.net/p/disklrucache Android本地缓存DiskLruCache完整详细学习示例 http://www.2cto.com/kf/201501/368172.html 虽然利用内存来缓存,加载图片的时候速度比较快,但是像GridView会很快地占满内存。当应 用非正常关闭(如被电话应用打断、运行在后台的时候被杀死)会导致cache被销毁清空。 注意:获取图片应该在后台进行 Of course, fetching images from disk is slower than loading from memory and should be done in a background thread, as disk read times can be unpredictable.(from google doc) 缓存位置: 有外部存储设备就存放到外部存储设备中,否则存放到应用包名目录下。 2.布局优化 sdk下的一些工具并不是专门针对Eclipse的,Android Studio也可以使用。 sdk/tools下的工具Hierarchy Viewer http://wear.techbrood.com/training/improving-layouts/optimizing-layout.html#Inspect 爽处1:可以查看布局结构某个节点的3个方法Measure、Layout、Draw执行所需要的时间,这样 如果某个item的加载时间比较长,你就应该要优化了。 使用这个工具可能会遇到的问题: 问题:使用Hierarchyviewer,measure、layout、draw时间未显示? 解决办法:点击菜单ProfileNode,重新加载之后就有了 用Hierarchyviewer,measure、layout、draw时间未显示? 本文转自屠夫章哥 51CTO博客,原文链接:http://blog.51cto.com/4259297/1710561,如需转载请自行联系原作者