通过《Picasso源码解析(一)》知道,在使用Picasso的load方法进行加载图片的时候实际上是创建了一个RequestCreator对象,这个RequestCreator对象,并且通过该对象创建了Request对象。 我们应该能猜想得到能灵活的决定某个或者某些图片(比如GridView里面的图片)是否需要进行缓存,这是图片加载库必实现的功能。在ImageLoader中调用displayImage方法来加载图片显示的时候可以传一个DisplayImageOptions来设定当前加载的图片是否需要memory cache或者disk cache(详细说明点此).事实上从某方面来说Request也扮演着跟DisplayImageOptions一样的角色!那么如何设置一个或某个图片是否需要进行memory cache或者disk cache呢? 在RequestCreator方法里面提供了memoryPolicy和networkPolicy两个方法分别设置是否需要对目标图像进行内存缓存和文件缓存:
/**设置文件缓存,返回的仍然是RequestCreator对象**/
//配置对当前请求是否内存缓存
private int memoryPolicy;
//配置对当前请求是否文件缓存
private int networkPolicy;
public RequestCreator memoryPolicy(
@NonNull MemoryPolicy policy,
@NonNull MemoryPolicy... additional) {
。。省略部分代码。。
this.memoryPolicy |= policy.index;
。。省略部分代码。。
if (additional.length > 0) {
for (MemoryPolicy memoryPolicy : additional) {
。。省略部分代码。。
this.memoryPolicy |= memoryPolicy.index;
}
}
return this;
}
查看MemoryPolicy的具体实现,我们可以用如下调用对当前Image不使用缓存(以在某种情况下减少内存压力):
Picasso.with(context)
.load(imageUrl)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE).
其中NO_CACHE正如源码注释所说:它表示在加载图片的过程中忽略缓存,也就是不从缓存中查找图片;而NO_STORE见名知意就是在图片加载完成后不对加载好的图片进行内存缓存。 同理如果对当前请求的图片禁止文件缓存,可以如下调用:
Picasso.with(context)
.load(imageUrl)
.networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE).
同时NetworkPolicy还提供了OFFLINE选项,表明当前请求(request)只通过disk memory获取,不通过网络请求.当然上面只是简单的说明了一下,事实上根据DownLoader的不同(是否使用OKhttp实现),NO_CACHE和NO_SOTRE的使用时不一样的(本篇不做说明)。 配置好上面的两个方法之后,在RequestCreator的into方法里面会有如下调用:
public void into(ImageView target, Callback callback) {
。。省略了部分重要代码。。
if (shouldReadFromMemoryCache(memoryPolicy)) {//是否需要从缓存中获取
//从缓存中获取bitmap
Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);//
if (bitmap != null) {//缓存成功
picasso.cancelRequest(target);
//调用PicassoDrawable的setBitmap方法(简单说明见博客一)
setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled);
//加载完成回调
if (callback != null) {
callback.onSuccess();
}
return;
}
}
}
而在进行网络加载的时候也同样根据上面的配置进行了判断,只是判断的方式与上面不同而已,这点不是本篇博客讲解的重点,暂且忽略之。 其实以上这些调用处理过后返回的都是RequestCreator对象,不要因为上面的说明就觉得RequestCreator有这么多的职责。其实RequestCreator主要职责是Create Request!!!真确的应该说是创建Request.Builder对象,然后初始化Builder对象完成后createRequest来创建一个Request对象(Builder模式的简单应用)!
Action解析沿着Picasso->load->into这条源码调用路径就是知道,Picasso提交的不是Request而是一个Action对象,博客一对Action做了一些简单的说明,本篇就详细的说一下它。 Action对象是一个封装了Request的对象!这个抽象类提供了,提供了complete和error两个抽象方法供子类实现。其中complete方法里面有个Bitmap参数,这就是即将要显示在ImageView中的bitmap了。Picasso中所有的Action如下图: ImageViewAction:这个就不用多说了,当你调用into(ImageView target)和into(ImageView target, Callback callback)的时候最终Picasso提交的就是这货!并且实现了complete方法,在该方法里最终调用PicassoDrawable.setBitmap来完成图片的显示!(可参考《Picasso源码的简单解析(一)》
FetchAction:当调用Picasso->load->fetch()/fetch(callback)的时候Picasso提交的就是这个Action!fetch()方法也是调用的fetch(null).那么这个Action的作用是什么呢?先看其图片加载完成后的complete/error方法都做了些什么:
@Override void complete(Bitmap result, Picasso.LoadedFrom from) {
if (callback != null) {
callback.onSuccess();
}
}
@Override void error() {
if (callback != null) {
callback.onError();
}
}
只是简单的调用了callback方法的onSuccess/onError方法。那么如果在调用fetch方法的时候不传入callback对象呢?那加载完成后就会什么都不会做,那FetchAction或者应该说fetch方法到底有什么用呢?在回答这个问题之前让我们看看fetch方法的实现:
public void fetch(@Nullable Callback callback) {
。。。省略部分代码。。
//创建请求对象
Request request = createRequest(started);
if (shouldReadFromMemoryCache(memoryPolicy)) {//读取内存
Bitmap bitmap = picasso.quickMemoryCacheCheck(key);
if (bitmap != null) {
//仍然是调用callback的onSuccess
if (callback != null) {
callback.onSuccess();
}
return;
}
}
Action action =
new FetchAction(picasso, request, memoryPolicy, networkPolicy, tag, key, callback);
//提交action
picasso.submit(action);
}
}
可以看出只是简单的读取内存中的bitmap,读取成功后调用callback的onSucess方法。其实看到这儿你应该已经明白了,这个fetch方法主要做的就是提交(submit)Action之后对图片进行加载后放入缓存里面去!说白了就是对图片进行预加载或者预先下载下来放入缓存里面,然后根据合适的时机在调用into方法来显示图片的作用! 所以根据上面的说明下面的调用是不对的(当然相信也没人会这么做):
Picasso.with(context)
.load(imageUrl)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE).
.networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
.fetch()
GetAction:这个Action很光棍,对最终生成的bitmap 不做任何处理,交给调用者使用。那么这个GetAction调用呢?答案是在RequestCreator的get()方法里,这个方法是一个同步方法,而且不能在UI线程中使用!至于为什么不能在UI线程中使用,先看它的具体实现:
public Bitmap get() throws IOException {
checkNotMain();//确保是非UI线程
。。。省略部分代码。。。
Request finalData = createRequest(started);
String key = createKey(finalData, new StringBuilder());
//创建GetAction
Action action = new GetAction(picasso, finalData, memoryPolicy, networkPolicy, tag, key);
return forRequest(picasso, picasso.dispatcher, picasso.cache, picasso.stats, action).hunt();
}
在Picasso中只有这个GetionAction没有经过Dispatcher的分发,直接交给forRequest方法进行处理(详细解说《picasso源码的简单解析(一)》),通过forRequest方法找出能处理该请求的RequestHandler之后,交给hunt调用ReqeustHandler的load方法进行处理,因为这个ReqeustHandler可能是从网络或者其他地方加载图片,很有可能会使得页面卡顿或者ANR,所以get()方法会 首先检测如果是在UI线程中,直接抛出异常;所以只能在非UI线程中使用:
new Thread() {
public void run() {
final Bitmap bitmap = Picasso.with(context).load(url).get();
mHandler.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(bitmap);
}
});
}
}.start();
不过个人觉得这个方法的实际使用意义或者 作用倒是不大。