源码分析: 图片加载框架Picasso源码分析
使用:
Picasso.with(this)
.load("http://imgstore.cdn.sogou.com/app/a/100540002/467502.jpg")
.into((ImageView) findViewById(R.id.ivImage));
(1),首先进入Picasso.with(this):
创建一个Picasso类型单例singleton, 接着进入Builder构造函数:
这里是通过传入的context获取全局的context,主要是为了防止内存泄漏, 接着我们看build方法:
先简要分析一下这里的主流程,后面再进行详细分析:
首先创建一个Downloader,看名字猜测应该是用于下载图片的; 接着创建一个LruCache用于图片的内存缓存; 然后创建一个ExecutorService子类PicassoExecutorService的线程池对象,用于执行具体的下载图片任务; 然后再创建一个请求转换器RequestTransformer对象(具体干嘛的目前还不知道,看名字猜测是做一些什么装换); 接着创建一个Stats对象(具体干嘛的目前还不知道,看名字猜测和状态有关); 然后再创建一个分发器Dispatcher对象,用于分发多个图片的请求到线程池里的线程去执行;
最后,创建了一个Picasso对象返回.
(2)进入load函数:
首先判断图片路径是否为null,是的话则创建一个uri为null的请求生成器RequestCreator(应该是用来生成图片加载请求的);如果非null但url长度为0,则直接抛出异常;否则进入load的重载方法:
根据图片路径path解析出相应的uri构建一个RequestCreator对象返回.
(3)接下来看into方法,最终会调用into(ImageView target, Callback callback)方法:
首先通过checkMain方法检查是否在主线程调用,不是在主线程则直接抛出异常(代码略),然后判断imageView是否为空,为空则抛出异常.
这段代码是判断是否要延期处理,我们没有延期,直接跳过.
这里首先根据开始时间创建一个请求,根据请求创建一个请求的key;
然后根据内存缓存策略判断是否需要从内存中读取缓存图片,默认需要;
如果需要从内存读取,则从内存读取图片,读取出来的图片如果非空,则返回,不用发起网络请求了;
如果回调接口非空,则回调成功(我们这里是null,不管).
先判断是否设置了占位图片,如果设置了则先显示占位图;
接着创建一个Action对象,然后将这个action对象加入队列并提交到线程池执行.
接着我们看看enqueueAndSubmit方法具体干了啥:
首先获取上一步创建Action时设置的ImageView对象target, 如果target非空并且在Map对象targetToAction里已经存在这个action,则取消已经存在的请求,并且将这个action存入map;
然后提交执行这个Action.
分发器将这个action进行分发,其实就是通过handler发送一条REQUEST_SUBMIT类型的消息,接着handler收到这条消息后进行处理.
首先判断Set集合pausedTags里是否包含action的key,这里初次请求是不包含的,略过;
接着在Map对象里通过action的key获取BitmapHunter,初次请求这里获取的位空.
首先判断线程池是否关闭,如果关闭了则返回;
接着通过forRequest方法创建一个BitmapHunter对象;
最后将这个BitmapHunter(实现了Runnable接口,具体这个runnable干什么我们后面分析)提交到线程池执;
最后它存入map,下次就可以直接取图片了.
下面我们详细分析:
在forRequest方法里通过picasso.getRequestHandlers()获取请求处理器list,这些处理器如下:
判断请求处理器能否处理本次请求,能处理则构造相应的BitmapHunter.
具体如何判断,我们看看RequestHandler的canHandleRequest方法,这里以NetworkRequestHandler为例:
主要是通过scheme进行判断, 所以这里返回的RequestHandler就是NetworkRequestHandler.
接着我们看看这个BitmapHunter具体干了些什么:
![](https://images2015.cnblogs.com/blog/774260/201701/774260-20170105224200206-429585625.png)
这里主要是通过hunt方法获取图片,通过获取的结果进行分发,我们继续看看hunt方法干了啥:
这里是从内存里读取图片的相关操作.
这里是根据网络策略进行图片读取,这里的OFFLINE是disk only,接着我们看看具体怎么读取?
这里通过downloader进行加载图片(具体如何加载下面说),然后返回.
先是根据缓存策略设置缓存控制(http缓存),接着使用OkHttpClient加载图片.
貌似没有磁盘缓存? 我们看看Downloader的构建过程:
在构建Downloader的时候,设置了默认的缓存路径,使用http缓存代替disk缓存.(该库和其他下载图片库的主要区别之一:使用4.0+系统上的HTTP缓存来代替Disk磁盘缓存)
关于http缓存,请参考以下文章: