您当前的位置: 首页 > 

郭梧悠

暂无认证

  • 3浏览

    0关注

    402博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Picasso源码的简单解析(二)

郭梧悠 发布时间:2016-08-03 22:58:50 ,浏览量:3

Request简单分析

通过《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();

不过个人觉得这个方法的实际使用意义或者 作用倒是不大。

关注
打赏
1663674776
查看更多评论
立即登录/注册

微信扫码登录

0.0388s