我们分步来实现,首先是图片的压缩,还是用之前学到的Bitemap.Options的inSampleSize。我们命名为ImageResizer的类来实现图片的压缩。
接着我们选择LruChache和DiskLruChache来分别完成内存缓存和磁盘缓存。在ImageLoader初始化时,我们创建LruChache和DiskLruChache:
其中还有对DiskLruChache的容错就是sd卡容量不足时,磁盘缓存将无效。接下来就是提供方法来添加和获取。首先是内存缓存:
而磁盘缓存的添加在之前说过使用Editor来完成的,Editor提供了commit和abort的方法,具体参考下面的loadBimapFromHttp方法。磁盘缓存的读取是通过Snapshot来完成,通过Snapshot可以得到缓存对象对应的FileInputStream,但是FileInputStream无法用BitmapFactroty的核心解析来加载Bitmap,所以要用到描述符,最后加载Bitmap。
同步加载和异步加载接口的设计:
首先看同步加载,同步加载接口需要外部在线程中使用,这是因为同步加载很可能比较耗时,它的实现如下:
在loadBitmap中,首先尝试从内存缓存中通过url来读取图片,接着尝试从磁盘中读取图片,如果都没有图片,则才从网络中去拉取图片。这个方法不能在主线程中调用,否则会抛出异常,这个环境是在loadBitmapFromHttp中实现的,通过检查当前线程的Looper是否为主线程来判断是否为主线程,如果是主线程则抛出异常。
接下来是异步加载的接口:
异步加载中,首先现查看内存是否有Bitmap,有就直接加载,没有就在线程池中去掉用loadBitmap方法,当图片加载完毕后,就将图片,图片的地址以及要绑定的ImageView绑定成一个LoaderResult对象,然后再通过mMainHandler向主线程发送一个消息,消息的obj就是这个LoaderResult,这样就可以在主线程中的imageView设置图片了,之所以要Handler是因为子线程无法访问UI。
bindBitmap里用到了线程池和Handler,线程池通过THREAD_POOL_EXECUTOR,实现如下:
我们用线程池去加载图片而不是用普通的线程,是因为随着列表的滑动可能会产生大量的线程,所以线程池容易管理。接下来是Handler,ImageLoader直接采用主线程的Looper来构造Handler对象,这就使得ImageLoader可以在非主线程中构造了。另外为了解决由于view复用导致的列表错位一问题,在给ImageView设置图片之前要查看它的url有没有发生改变,如果改变了就不设置了。
最后
最后这里放上我这段时间复习的资料,这个资料也是偶然一位朋友分享给我的,里面包含了腾讯、字节跳动、阿里、百度2020-2021面试真题解析,并且把每个技术点整理成了视频和PDF(知识脉络 + 诸多细节)。
还有 高级架构技术进阶脑图、高级进阶架构资料 帮助大家学习提升进阶,这里我也免费分享给大家也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
一起互勉~
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**