Picasso2:Picasso load(参数)方法详解。

1.Picasso load(参数)方法详解。

url,文件的path路径,资源id...
最终都会返回一个RequestCreator对象(图片加载请求)。

// Picasso.java
public RequestCreator load(String path) {
    if(path == null){
        return new RequestCreator(this, (Uri)null, 0);
    } else if(path.trim().length() ==0) {
        throw new  IllegalArgumentException("Path must not be empty.");
    } else {
        return this.load(Uri.parse(path));
    }
}

2.Picasso into(iv)方法详解。正式加载图片。

//RequestCreator.java
public void into(ImageView targetr){
    this.into(target, (Callback)null);//2.1
}
//2.1
public void into(ImageView target,Callback callback){
    long started = System.nanoTime();
    Utils.checkMain();
    if(target ==null){
        throw new IllegalArgumentException("Target must not be null.");
    } else if(!this.data.hasImage()){ //uri或资源id 非空
        this.picasso.cancelRequest(target);//2.2 取消图片请求
        if(this.setPlaceholder){ //设置占位符
            PicassoDrawable.setPlaceholder(target, this.getPlaceholderDrawable());
        }   
    } else {
        if(this.deferred){  // 是否延迟加载
            if(this.data.hassize()){
                throw new IllegalStateException("Fit cannot be used with resize.");
            }
            int width = target.getWidth();
            int height = target.getHeight();
            if (width == 0 || height == 0) {
                if (setPlaceholder) {
                    setPlaceholder(target, getPlaceholderDrawable());
                }
                picasso.defer(target, new DeferredRequestCreator(this, target, callback));
                return;
            }
            data.resize(width, height);
        }
        // 这里主要是如果之前自定义了transform,会发生在这个方法(之前说过我们为您一般也不需要定义这个东西)
        Request request = createRequest(started);
        // 这里其实主要是将request和key关联,和我们之前说key可以理解为标识就有了联系
        String requestKey = createKey(request);
        // 是否在内存缓存中读取数据
        if (shouldReadFromMemoryCache(memoryPolicy)) {
            // 从缓存中获取bitmap
            Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
            if (bitmap != null) {
                // 取到bitmap,就把网络请求撤销。【重点方法】
                picasso.cancelRequest(target);
                setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled);
                if (picasso.loggingEnabled) {
                    log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY);
                }
                // 成功回调这个方法,在基本使用中我们是使用过的
                if (callback != null) {
                    callback.onSuccess(); //成功加载图片的回调方法
                }
                return;
            }
        }
        // 设置占位图
        if (setPlaceholder) {
            setPlaceholder(target, getPlaceholderDrawable());
        }

        Action action =
                new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,
                        errorDrawable, requestKey, tag, callback, noFade);
        // 最后开始提交任务
        picasso.enqueueAndSubmit(action);
    }   
}

boolean hasImage() {
    return this.url!=null || this.resourceId !=0;
}
// 2.2.1
public void cancelRequest(ImageView view){
    this.cancelExistingRequest(view); // 2.2.2
}
// 2.2.3
private void cancelExistingRequest(Object target){
    Utils.checkMain();
    //Action 是request的包装类。里面有Picasso和Request等。
    //其中包含了很多的其他东西,比如缓存策略,Picasso对象,
    Action action = (Action)this.targetToAction.remove(target);
    if(action != null){
        action.cancel();
        this.dispatcher.dispatchCancel(action);//2.2.4取消请求 
    }   
    if(target instanceof ImageView){ 
        ImageView targetImageView=(ImageView)target;
  //DeferredRequestCreator 是RequestCreator的包装类,是为了对ImageView的监听,
  //跟进去,会发现getViewTreeObserver来监听,获取如具体的宽高等,因此也需要移除。
        DeferredRequestCreator deferredRequestCreator = (DeferredRequestCreator)this
            .targetToDeferredRequestCreator.remove(targetImageView);
        if(deferredRequestCreator != null){
            deferredRequestCreator.cancel();
        }
    }
}
//Dispatcher
//2.2.4
void dispatchCancel(Action action) {
  this.handler.sendMessage(this.handler.obtainMessage(2,action)); //2.2.5
}
//Dispatcher.DispatchHandler. handleMessage(msg)
public void handleMessage(Message msg){
    //...
    case 2: //2.2.5
        info3 = (Action)msg.obj;
        this.dispatcher.performCancel(info3); //2.2.6
    break;
}
//2.2.6
void performCancel(Action action) {
    String key = action.getKey();
    //2.2.7【核心类】可开启线程下载;可解码处理bitmap;可做图片旋转工作;是一个开启子线程的工具
    BitmapHunter hunter = (BitmapHunter)this.hunterMap.get(key);
    //....
    if(hunter!=null) {}
    if(this.pauseTags.contains(action.getTag())){}
}
//2.2.7 BitmapHunter实现了Runnable接口,我们要关注的是他的run方法
@Override public void run() {
    try {
      updateThreadName(data);//修改线程名称
      if (picasso.loggingEnabled) {
        log(OWNER_HUNTER, VERB_EXECUTING, getLogIdsForHunter(this));
      }
      // 获取图片(首先通过内存,不行在通过网络,用okhttp3)
      result = hunt();//线程的核心,拿到结果。
    
      if (result == null) {
        dispatcher.dispatchFailed(this);
      } else {
        dispatcher.dispatchComplete(this);//成功的回调
      }
    } catch (NetworkRequestHandler.ResponseException e) {
      if (!NetworkPolicy.isOfflineOnly(e.networkPolicy) || e.code != 504) {
        exception = e;
      }
      dispatcher.dispatchFailed(this);
    } catch (IOException e) {
      exception = e;
      dispatcher.dispatchRetry(this);
    } catch (OutOfMemoryError e) {
      StringWriter writer = new StringWriter();
      stats.createSnapshot().dump(new PrintWriter(writer));
      exception = new RuntimeException(writer.toString(), e);
      dispatcher.dispatchFailed(this);
    } catch (Exception e) {
      exception = e;
      dispatcher.dispatchFailed(this);
    } finally {
      Thread.currentThread().setName(Utils.THREAD_IDLE_NAME);
    }
}



Action.java

createRequest

private Request createRequest(long started){//创建加载图片的请求
    Request request = this.data.build();
    Request transformed = this.picasso.transformRequest(request);
}
//ImageViewAction.java
class ImageViewAction extends Action<ImageView>{
    ImageViewAction(Picasso picasso,ImageView imageView,Request data,int memoryPolicy, ...){
        super(picasso,imageView,data,memoryPolicy,networkPolicy,errorResId,errorDrawable,key...);
        this.callback=callback;
    }
}
//Action.java
Action(Picasso picasso,T target,Request,...){
    this.target = target==? null: new Action.RequestWeakReference(this,target,...)
}
//enqueueAndSubmit
void enqueueAndSubmit(Action action) {
    // 获取请求操作的对象
    Object target = action.getTarget();
    // 判断object和action是否匹配(这个object可以是ImageView,而action又是
    //request的包装类,这一下,两者的结合就比较明白了(请求操作对象和具体的请求)
    if (target != null && targetToAction.get(target) != action) {
      // This will also check we are on the main thread.
      // 发现不匹配,取消请求
      cancelExistingRequest(target);
      // 将此时两者关联(也就是放在一个map集合当中),缓存以备复用
      targetToAction.put(target, action);
    }
    // 继续任务提交
    submit(action);
}
void submit(Action action){
    this.dispatcher.dispatchSubmit(action);
}
void dispatchSubmit(Action action){
    this.handler.sendMessage(this.handler.obtainMessage(1, action));
}
//Dispatcher.DispatchHandler. handleMessage(msg)
public void handleMessage(Message msg){
    //...
    case 1: 
        info3 = (Action)msg.obj;
        this.dispatcher.performSubmit(info3);
    break;
}
void performSubmit(Action action){
    this.performSubmit(action, true);
}

void performSubmit(Action action, boolean dismissFailed) {
    // 判断是否延迟暂停加载(就是之前是否设置过暂停延迟的标记)
    if (pausedTags.contains(action.getTag())) {
        // 同样将target和action关联(此时存放发延迟加载),存放以便于后来的唤醒请求
        pausedActions.put(action.getTarget(), action);
        if (action.getPicasso().loggingEnabled) {
            log(OWNER_DISPATCHER, VERB_PAUSED, action.request.logId(),"because tag '" + action.getTag() + "' is paused");
        }
        return;
    }

    // 获取请求的图片捕获器(就是一个runnable,说过,key可以当成bitmap和请求的标记)
    BitmapHunter hunter = hunterMap.get(action.getKey());
    if (hunter != null) {
        // 这里是对hunter的action初始化并进行健壮性判断
        hunter.attach(action);
        return;
    }
    // 判断当前线程池是否关闭
    if (service.isShutdown()) {
        // 如果关闭,打印日志,直接结束
        if (action.getPicasso().loggingEnabled) {
            log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
        }
        return;
    }
    
    // 未关闭:这个方法主要是找到能够处理相应请求request的requestHandler,并封装成BitmapHuntere返回
    hunter = forRequest(action.getPicasso(), this, cache, stats, action);
    // ****** 交给线程池service处理(获取图片),关注BitmapHunter的run方法(之前讲过了),future保存结果
    hunter.future = service.submit(hunter);
    // 关联,将key和hunter关联
    hunterMap.put(action.getKey(), hunter);
    if (dismissFailed) {
        failedActions.remove(action.getTarget());
    }

    if (action.getPicasso().loggingEnabled) {
        log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
    }
}
//PicassoExecutorService.java
public Future<?> submit(Runnable task){
  //PicassoFutureTask 便于控制处理的线程  
  PicassoExecutorService.PicassoFutureTask ftask = new PicassoExecutorService.PicassoFutureTask();  
  this.execute(ftask); //开启线程
  return ftask;  
}

static BitmapHunter forRequest(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats, Action action) {
    Request request = action.getRequest();
    List<RequestHandler> requestHandlers = picasso.getRequestHandlers();

    // 此函数的核心在于这里,根据request的不同,选择匹配的requesthandler
    // 所有的requesthandler都继承抽象类requestHandler,其中的核心方法是load
    // 根据不同的图片来源选择不同的加载方式,比如assets文件夹中的图片和网络图片的加载方式肯定不一样
    // 加载网络图片用的是NetworkRequestHandler
    // 对于这个请求不确定性和多个处理器都有机会处理的请情况,可以看做是责任连模式的简单应用
    for (int i = 0, count = requestHandlers.size(); i < count; i++) {
        RequestHandler requestHandler = requestHandlers.get(i);
        if (requestHandler.canHandleRequest(request)) {
            return new BitmapHunter(picasso, dispatcher, cache, stats, action, requestHandler);
        }
    }
    return new BitmapHunter(picasso, dispatcher, cache, stats, action, ERRORING_HANDLER);
}

void attach(Action){
    //...
    this.actions.add(action); //加入List集合当中
    //更新优先级
    this.priority = actionPriority;
}

3.线程池在哪里执行。

//PicassoExecutorService.java 
private static final class PicassoFutureTask extends FutureTask<BitmapHunter> implements ***
{
    private final BitmapHunter hunter;
    public PicassoFutureTask(BitmapHunter hunter) {
        super(hunter, (Object)null);
        this.hunter=hunter;
    }
}

//【重点方法】
Result hunt() throws IOException {
    //是否是内存模式读取
    if (shouldReadFromMemoryCache(data.memoryPolicy)) {
      Bitmap bitmap = cache.get(key);
      if (bitmap != null) {
        stats.dispatchCacheHit();
        if (picasso.loggingEnabled) {
          log(OWNER_HUNTER, VERB_DECODED, data.logId(), "from cache");
        }
        return new Result(bitmap, MEMORY);
      }
    }
 
    //确认重连次数
    if (retryCount == 0) {
      data = data.newBuilder().networkPolicy(NetworkPolicy.OFFLINE).build();
    }
 
    final AtomicReference<Result> resultReference = new AtomicReference<>();
    final AtomicReference<Throwable> exceptionReference = new AtomicReference<>();
    final CountDownLatch latch = new CountDownLatch(1);
    try {
      //在本例中因为是网络请求,使用的是NetworkRequestHandler, 这是通过查看
      //其中的load会得知使用的完全是okhttp的下载方法。
      requestHandler.load(picasso, data, new RequestHandler.Callback() {
        @Override public void onSuccess(@Nullable Result result) {
          resultReference.set(result);
          latch.countDown();
        }
 
        @Override public void onError(@NonNull Throwable t) {
          exceptionReference.set(t);
          latch.countDown();
        }
      });
 
      latch.await();
    } catch (InterruptedException ie) {
      InterruptedIOException interruptedIoException = new InterruptedIOException();
      interruptedIoException.initCause(ie);
      throw interruptedIoException;
    }
 
    //如果出现异常。则抛出
    Throwable throwable = exceptionReference.get();
    if (throwable != null) {
      if (throwable instanceof IOException) {
        throw (IOException) throwable;
      }
      if (throwable instanceof Error) {
        throw (Error) throwable;
      }
      if (throwable instanceof RuntimeException) {
        throw (RuntimeException) throwable;
      }
      throw new RuntimeException(throwable);
    }
 
    Result result = resultReference.get();
 
    if (result.hasBitmap()) {
      if (picasso.loggingEnabled) {
        log(OWNER_HUNTER, VERB_DECODED, data.logId());
      }
      Bitmap bitmap = result.getBitmap();
      stats.dispatchBitmapDecoded(bitmap);
 
      //根据需求对bitmap进行剪裁
      int exifOrientation = result.getExifRotation();
      if (data.needsTransformation() || exifOrientation != 0) {
        if (data.needsMatrixTransform() || exifOrientation != 0) {
          bitmap = transformResult(data, bitmap, exifOrientation);
          if (picasso.loggingEnabled) {
            log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId());
          }
        }
    
        //如果设置了transFrom那么进行变换。
        result = new Result(bitmap, result.getLoadedFrom(), exifOrientation);
        if (data.hasCustomTransformations()) {
          result = applyCustomTransformations(data.transformations, result);
          if (picasso.loggingEnabled) {
            log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId(),
                "from custom transformations");
          }
        }
      }
      if (result.hasBitmap()) {
        stats.dispatchBitmapTransformed(result.getBitmap());
      }
    }
 
    return result;
  }

void dispatchCacheHit(){
    this.handler.sendEmptyMessage(0);
}
//Stats.StatsHandler  StatsHandler()
case 0: this.stats.performCacheHit(); break;
// 缓存命中++
void performCacheHit(){
    ++ this.cacheHits;
}
//NetworkRequestHandler.java
public Result load(Request request,int networkPolicy) throws IOException{
    //下载器加载
    Response response = this.downloader.load(request.uri, request.networkPolicy);
    if(response == null) return null;
    else {
        LoadedFrom loadedFrom = response.cached?LoadedFrom,DISK:LoadedFrom.NETWORK;
        Bitmap bitmap=response.getBitmap();
        if(bitmap!=null) return new Result(bitmap, loadedFrom);
        else {
            InputStream is=response.getInputStream();
            if(is==null) return null;
            else if(loadedFrom == LoadedFrom.DISK && response.getContentLength()== 0L){
                Utils.closeQuietly(is);
                throw new NetworkRequestHandler.ContentLegnthException("");
            }
        }
    }
}

4. // Downloader.java 接口,

具体的实现 OkHttpDownloader, UrlConnectionDownloader 的区别。

4.1 OkHttpDownloader 的实现。

public Response load(URI uri, int networkPolicy)throws IOException {
    CacheControl cadhecontrol=null;
    if(networkPolicy!=0){
        if(NetworkPolicy.isOffline0nly(networkPolicy)){
            cacheControl=CacheControl.FORCE_CACHE;
        }else{ 
            Builder builder=new Builder();
            if(!NetworkPolicy.shouldReadFromDiskCache(networkPolicy)){
                builder.noCache();//非内存缓存读取数据
            }
            if(!NetworkPolicy.shouldwriteToDiskCache(networkPolicy)){
                builder.nostore();//非硬盘缓存读取数据
            }
            cacheControl = builder.build();
        }
    }
    com.squareup.okhttp.Request.Builder builder1 =(new com.squareup.okhttp.Request.Builder()).url(uri.toString());
    if(cachecontrol != null) builder1.cachecontrol(cachecontrol);   
    
    //调用同步请求
    com.squareup.okhttp.Response response = this.client.newCall(builder1.build()).execute();
    int responseCode = response.code();
    if(responseCode>=300) {
        response.body().close();
        throw new ResponseException(responseCode + " "+response.message());
    }else {
        boolean fromCache =response.cacheResponse() !=null;
        ResponseBody responseBody =response.body();
        return new Response(responseBody.byteStream(),fromCache, responseBody.contentLength());
    }
}

4.2 UrlConnectionDownloader 的实现。

public Response load(Uri uri, int networkPolicy)throws IOException {
    if(VERSION.SDK INT>= 14){installCacheIfNeeded(this.context);}
    
    HttpURLConnection connection =this.openConnection(uri);
    connection.setUseCaches(true);//开启缓存
    if(networkPolicy!=0) {
        String responseCode;
        if(NetworkPolicy.isOfflineOnly(networkPolicy))
        {
            responseCode = "only-if-cached,max-age=2147483647";
        }else
        {
            StringBuilder contentLength =(StringBuilder)CACHE_HEADER_BUILDER.get();
            contentLength.setLength(0);
            if(!NetworkPolicy.shouldReadFromDiskCache(networkPolicy)){
                contentLength.append("no-cache");
            }
            if(!NetworkPolicy.shouldwriteToDiskCache(networkPolicy)){
                if(contentLength.length()>0) {
                    contentLength.append(',');
                }
                contentLength.append("no-store");
            }
            responseCode= contentLength.toString();
        }
        connection.setRequestProperty("Cache-Control", responseCode);
    }
    int responseCode1 = connection.getResponseCode();
    if(responseCode1 >=300 ) {
        connection.disconnect();
        throw new ResponseException(responseCode + " "+response.message());
    }else {
        long contentLength1 =(long)connection.getHeaderFieldInt("Content-Length",-1);
        boolean fromCache = Utils.parseResponseSourceHeader(connection,getHeaderField("X-Andro");
        return new Response(connection.getInputStream(),fromCache, contentLength1);
    }
}

5.into方法,完成加载。

BitmapHunter.run()

BitmapHunter.run()
    ↓
dispatcher.dispatchComplete(this);//成功的回调
    ↓
this.handler.sendMessage(this.handler.obtainMessage(4, hunter);
    ↓
case 4:
{
    info2 = (BitmapHunter)msg.obj;
    this.dispatcher.performComplete(info2);
} break;
    ↓
void performComplete(BitmapHunter hunter){
    if(MemoryPolicy.shouldWriteToMemoryCache(hunter.getMemoryPolicy())){
        this.cache.set(hunter.getKey(), hunter.getResult()); //结果保存到cache 缓存中
    }    
    this.hunterMap.remove(hunter.getKey());//移除hunter.getKey(),请求已完成,避免重复请求
    this.batch(hunter);//
    if(hunter.getPicasso().loggingEnabled){
        Utils.1og("Dispatcher"."batched",Utils.getLogIdsForHunter(hunter),"for completion");
    }
}
private void batch(BitmapHunter hunter){
    if(!hunter.isCancelled()) {
        this.batch.add(hunter); //存放到list集合中
        if(!this.handler.hasMessages(7)){
            this.handler.sendEmptyMessageDelayed(7, 200L);
        }
    }
}
// handleMessage()
case 7: this.dispatcher.performBatchComplete();

// performBatchComplete()
void performBatchComplete(){
    ArrayList copy=new ArrayList(this.batch);
    this.batch.clear(); //清理以前的batch集合
    //发消息给主线程处理。
    this.mainThreadHandler.sendMessage(this,mainThreadHandler.obtainMessage(8, copy));
    this.logBatch(copy);    
}   
//Picasso.deliverAction()
case 8:
    batch = (List)msg.obj;
    i =0;
    for(n=batch.size(); i<n; ++i){
        BitmapHunter var7 = (BitmapHunter)batch.get(i);
        var7.picasso.complete(var7);
    }
    break;
//complete()     
void complete(BitmapHunter hunter) {
    //...
    if(shouldDeliver) {
        Uri uri = hunter.getData().uri;
        Bitmap result = hunter.getResult();
        // 分发action
        this.deliverAction(result, from, single);
    }
}    
// deliverAction    
    action.complete(result, from); //complete是抽象方法,
//实现类ImageViewAction.java
public void complete(Bitmap result,LoadedFrom from) {
    if(result == null){
        throw new AssertionError("Attempted to complete action with no result!\n"); 
    }else {
        ImageView target=(ImageView)this.target.get();
        if(target != null){
            Context context=this.picasso.context;
            boolean indicatorsEnabled = this.picasso.indicatorsEnabled;
            PicassoDrawable.setBitmap(target,context,result, from, this.noFade, indicatorsEnabled);
            if(this.callback != null){
                this.callback.onSuccess();
            }
        }
    }
}

// PicassoDrawable.java
static void setBitmap(ImageView target, Context context, Bitmap bitmap, Loadedfrom loadedfrom,noFade, indicatorsEnabled) {
    Drawable placeholder=target.getDrawable();\
    if(placeholder instanceof AnimationDrawable) {
        ((AnimationDrawable)placeholder).stop();
    }
    PicassoDrawable drawable = new PicassoDrawable(context, bitmap, placeholder, loadedFrom, nof);
    target.setImageDrawable(drawable);  //设置图片。
}  

重点知识:handler+ 线程池。
------End-----------------

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容