美文网首页
Picassio源码分析

Picassio源码分析

作者: 不需要任何 | 来源:发表于2018-09-13 21:32 被阅读23次

    步骤

    get():

    双锁创建Picasso单例,通过Builder模式创建

    Picasso singleton;
    
      public static Picasso get() {
        if (singleton == null) {
          synchronized (Picasso.class) {
            if (singleton == null) {
              if (PicassoProvider.context == null) {
                throw new IllegalStateException("context == null");
              }
              singleton = new Builder(PicassoProvider.context).build();
            }
          }
        }
        return singleton;
      }
    
    private  Context;
     public Builder(@NonNull Context context) {
          if (context == null) {
            throw new IllegalArgumentException("Context must not be null.");
          }
        // 这里得到的是ApplicationContext的上下文
          this.context = context.getApplicationContext();
        }
    

    可以看到传入的只是Builder到这里只有一个上下文context

      public Picasso build() {
          Context context = this.context;
    
          if (downloader == null) {
            downloader = new OkHttp3Downloader(context);
          }
          if (cache == null) {
            cache = new LruCache(context);
          }
          if (service == null) {
            service = new PicassoExecutorService();
          }
          if (transformer == null) {
            transformer = RequestTransformer.IDENTITY;
          }
    
          Stats stats = new Stats(cache);
    
          Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);
    
          return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,
              defaultBitmapConfig, indicatorsEnabled, loggingEnabled);
        }
    

    调用build的时候,我们会创建多个东西:

    • downloader : OKHTTP的下载器
    • LruCache : 缓存器
    • PicassoExecutorService : 线程池服务
    • transformer : 变压器
      Picasso(Context context, Dispatcher dispatcher, Cache cache, Listener listener,
          RequestTransformer requestTransformer, List<RequestHandler> extraRequestHandlers, Stats stats,
          Bitmap.Config defaultBitmapConfig, boolean indicatorsEnabled, boolean loggingEnabled) {
        this.context = context;
        this.dispatcher = dispatcher;
        this.cache = cache;
        this.listener = listener;
        this.requestTransformer = requestTransformer;
        this.defaultBitmapConfig = defaultBitmapConfig;
    
        int builtInHandlers = 7; // Adjust this as internal handlers are added or removed.
        int extraCount = (extraRequestHandlers != null ? extraRequestHandlers.size() : 0);
        List<RequestHandler> allRequestHandlers = new ArrayList<>(builtInHandlers + extraCount);
    
        // ResourceRequestHandler needs to be the first in the list to avoid
        // forcing other RequestHandlers to perform null checks on request.uri
        // to cover the (request.resourceId != 0) case.
        allRequestHandlers.add(new ResourceRequestHandler(context));
        if (extraRequestHandlers != null) {
          allRequestHandlers.addAll(extraRequestHandlers);
        }
        allRequestHandlers.add(new ContactsPhotoRequestHandler(context));
        allRequestHandlers.add(new MediaStoreRequestHandler(context));
        allRequestHandlers.add(new ContentStreamRequestHandler(context));
        allRequestHandlers.add(new AssetRequestHandler(context));
        allRequestHandlers.add(new FileRequestHandler(context));
        allRequestHandlers.add(new NetworkRequestHandler(dispatcher.downloader, stats));
        requestHandlers = Collections.unmodifiableList(allRequestHandlers);
    
        this.stats = stats;
        this.targetToAction = new WeakHashMap<>();
        this.targetToDeferredRequestCreator = new WeakHashMap<>();
        this.indicatorsEnabled = indicatorsEnabled;
        this.loggingEnabled = loggingEnabled;
        this.referenceQueue = new ReferenceQueue<>();
        this.cleanupThread = new CleanupThread(referenceQueue, HANDLER);
        this.cleanupThread.start();
      }
    

    这里我们才真正真正初始化了单例Picasso ,最后传入对应的配置。接下开看看比较重要的:
    allRequestHandlers:是一个容器内部包裹了多个RequestHandler,用来解决不同的请求,举个例子,家里装了新家
    我们需要做的事情就是请工人安装,但是工人分为好几种,电工.管道.工装空调的等等他们各司其职 ,用来解决不同的场景,而这里我们就可以把他看成一个一个的“工人”。

    --

    load()

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

    这里可以看见调用load的时候我们进行判断过滤,输入的满足条件就可以开始创建RequestCreator

      RequestCreator(Picasso picasso, Uri uri, int resourceId) {
        if (picasso.shutdown) {
          throw new IllegalStateException(
              "Picasso instance already shut down. Cannot submit new requests.");
        }
        this.picasso = picasso;
        this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);
      }
    

    做了两点,传入picasso引用,创建Request.Builder ,这里load就结束了其实,我们发现返回的其实是包装好了的RequestCreator,而且RequestCreator内部包含引用data=Request.Builder,但是到目前为止我们什么都还没做,只是初始化了相关配置,创建了RequestCreator而已。

    into

    好戏现在才开始

    
      public void into(ImageView target, Callback callback) {
        long started = System.nanoTime();
        checkMain();
    
        if (target == null) {
          throw new IllegalArgumentException("Target must not be null.");
        }
    
        if (!data.hasImage()) {
          picasso.cancelRequest(target);
          if (setPlaceholder) {
            setPlaceholder(target, getPlaceholderDrawable());
          }
          return;
        }
    
        if (deferred) {
          if (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);
        }
    
        Request request = createRequest(started);
        String requestKey = createKey(request);
    
        if (shouldReadFromMemoryCache(memoryPolicy)) {
          Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
          if (bitmap != null) {
            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);
      }
      
      
       private Request createRequest(long started) {
        int id = nextId.getAndIncrement();
    
        Request request = data.build();
        request.id = id;
        request.started = started;
    
        boolean loggingEnabled = picasso.loggingEnabled;
        if (loggingEnabled) {
          log(OWNER_MAIN, VERB_CREATED, request.plainId(), request.toString());
        }
    
        Request transformed = picasso.transformRequest(request);
        if (transformed != request) {
          // If the request was changed, copy over the id and timestamp from the original.
          transformed.id = id;
          transformed.started = started;
    
          if (loggingEnabled) {
            log(OWNER_MAIN, VERB_CHANGED, transformed.logId(), "into " + transformed);
          }
        }
    
        return transformed;
      }
      
    
        boolean hasImage() {
          return uri != null || resourceId != 0;
        }
    
    1. 我们检查是不是在主线程
    2. 判断uri或者resourceId ,即来源是不是为空,为空就直接取消请求,设置占位图
    3. 是不是调用fit(),但是不能和resize一起用
    4. 创建Request实体,即Request.Builder.build(),这里有过滤然后设置该Request为普通
    5. 设置resourceId还有开始的时间
    6. createRequest(started)设置了transformed转换器的一个接口,实现该接口应该可以手动改变request,如果转换后的request变更我们就改变他
    7. 是不是需要在缓存中找,如果找到取消请求,设置图片,回调成功接口。
    8. 没有找到就设置占位图,创建一个Action,调用picasso.enqueueAndSubmit(action);

    Action 和 Requst的对比。

    如果查看区别的话,其实属性都可以查看出来:
    我们看看Request属性:

     int id;
      long started;
      int networkPolicy;
      public final Uri uri;
      public final int resourceId;
      public final String stableKey;
      public final List<Transformation> transformations;
      public final int targetWidth;
      public final int targetHeight;
      public final boolean centerCrop;
      public final boolean centerInside;
      public final boolean onlyScaleDown;
      public final float rotationDegrees;
      public final float rotationPivotX;
      public final float rotationPivotY;
      public final boolean hasRotationPivot;
      public final Bitmap.Config config;
      public final Priority priority;
    

    再来看看Action属性

    final Picasso picasso;
      final Request request;
      final WeakReference<T> target;
      final boolean noFade;
      final int memoryPolicy;
      final int networkPolicy;
      final int errorResId;
      final Drawable errorDrawable;
      final String key;
      final Object tag;
      boolean willReplay;
      boolean cancelled;
    

    我们可以看见Request跟注重的是他请求的本身 如:id,请求的来源等等 ,而Action更倾向于一个加载的任务而且它持有Request引用,还有任务的状态,各种策略等,所以是包含关系。

    回到代码中:

      void enqueueAndSubmit(Action action) {
        Object target = action.getTarget();
        if (target != null && targetToAction.get(target) != action) {
          // This will also check we are on the main thread.
          cancelExistingRequest(target);
          targetToAction.put(target, action);
        }
        submit(action);
      }
    
      void submit(Action action) {
        dispatcher.dispatchSubmit(action);
      }
    
    

    因为Target 是所谓的虚引用,然后拿出Target判断是不是和数组里的Target一样不一样就更新。最后交给了
    dispatcher.dispatchSubmit(action)

    Dispatcher

    中文译为分发者即 : 任务分发者

    • 他是在Picassio初始化的时候被创建的是
    • 每一个Dispatcher都关联了 线程池 下载器 缓存 监控器 以及主线程的Handler
    • 他是发动机,也是我们的控制或者说中心
    • Dispatcher内部有一个东西即 DispatcherHandler这是Dispatcher自己的Handler,他绑定的是Dispatcher子线程的Looper

    Dispatcher. dispatchSubmit():

    void dispatchSubmit(Action action) {
        handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action));
      }
    

    而这个handler就是我们之前聊到的DispatcherHandler,相当于把发送的任务交给了子线程,我看看接下来到底是怎样的吧:
    这里插一句 : 子线程handleMessage调用performSubmit方法不多讲中间过程不多讲

    oid performSubmit(Action action, boolean dismissFailed) {
    //注意哦,这里已经不在主线程了,而是在dispatcher线程(HandlerThread)
        if (pausedTags.contains(action.getTag())) {
          pausedActions.put(action.getTarget(), action);
          if (action.getPicasso().loggingEnabled) {
            log(OWNER_DISPATCHER, VERB_PAUSED, action.request.logId(),
                "because tag '" + action.getTag() + "' is paused");
          }
          return;
        }
    
        BitmapHunter hunter = hunterMap.get(action.getKey());
        if (hunter != null) {
          hunter.attach(action);
          return;
        }
    
        if (service.isShutdown()) {//线程池是否关闭
          if (action.getPicasso().loggingEnabled) {
            log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
          }
          return;
        }
    
        //创建hunter
        hunter = forRequest(action.getPicasso(), this, cache, stats, action);
        hunter.future = service.submit(hunter);
        hunterMap.put(action.getKey(), hunter);
        if (dismissFailed) {
          failedActions.remove(action.getTarget());
        }
    
        if (action.getPicasso().loggingEnabled) {
          log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
        }
      }
    
    1. 判断任务是不是被暂停了,如果暂停了就放入暂停的容器里
    2. 在通过 keyhuntermap中寻找有没有对应的hunter
    3. 判断是不是线程被关闭,不然就return
    4. 创建对应的Hunter ,等一会儿详细讨论它
    5. 调用直接把Hunter扔进去线程池中,为什么能直接扔,看下面
    6. 然后把Hunterkey为键值对放到hunterMap容器中

    BitmapHunter

    中文翻译 图像猎人 脑洞真大
    先看实现接口吧:

    class BitmapHunter implements Runnable
    

    实现了Runable的接口,这说明了上文的为什么可以直接扔进线程池的原因,所以等等我们思路就跟更加明了直接在run方法看线程池执行的过程
    不过在这之前我们得看看Hunter是如何创建的:

    static BitmapHunter forRequest(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats,
          Action action) {
        Request request = action.getRequest();
        List<RequestHandler> requestHandlers = picasso.getRequestHandlers();
    
        // Index-based loop to avoid allocating an iterator.
        //noinspection ForLoopReplaceableByForEach
        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);
      }
    

    你还记得之前创建的千万个RequestHandler吗?现在我们正调用canHandleRequest方法,一个一个对比他们的能力是不是和这个任务匹配,如果找到就创建BitmapHunter对象并且传入对应requestHandler引用。

    接下来,emm.....看Hunterrun方法

    @Override public void run() {
        try {
          updateThreadName(data);
    
          if (picasso.loggingEnabled) {
            log(OWNER_HUNTER, VERB_EXECUTING, getLogIdsForHunter(this));
          }
    
          result = hunt();
    
          if (result == null) {
            dispatcher.dispatchFailed(this);
          } else {
            dispatcher.dispatchComplete(this);
          }
        } catch (Downloader.ResponseException e) {
          if (!e.localCacheOnly || e.responseCode != 504) {
            exception = e;
          }
          dispatcher.dispatchFailed(this);
        } catch (NetworkRequestHandler.ContentLengthException e) {
          exception = e;
          dispatcher.dispatchRetry(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);
        }
      }
    

    我们只用关心两点:

    • 调用hunt “打猎” ,然后传回打猎的结果
    • 如果有结果 调用 dispatcher.dispatchComplete(this)否则调用dispatcher.dispatchFailed(this);

    然后看看怎么“打的猎吧”

    Bitmap hunt() throws IOException {
       Bitmap bitmap = null;
    
       //依然先从缓存拿
       if (shouldReadFromMemoryCache(memoryPolicy)) {
         bitmap = cache.get(key);
         if (bitmap != null) {
           stats.dispatchCacheHit();
           loadedFrom = MEMORY;
           if (picasso.loggingEnabled) {
             log(OWNER_HUNTER, VERB_DECODED, data.logId(), "from cache");
           }
           return bitmap;
         }
       }
    
       //缓存没有命中的话,再调用requestHandler.load
       data.networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy;
       RequestHandler.Result result = requestHandler.load(data, networkPolicy);
       //拿到结果
       if (result != null) {
         loadedFrom = result.getLoadedFrom();
         exifRotation = result.getExifOrientation();
          //从结果中拿bitmap
         bitmap = result.getBitmap();
    
         // If there was no Bitmap then we need to decode it from the stream.
         if (bitmap == null) {
           InputStream is = result.getStream();
           try {
           //压缩
             bitmap = decodeStream(is, data);
           } finally {
             Utils.closeQuietly(is);
           }
         }
       }
    
       if (bitmap != null) {
         if (picasso.loggingEnabled) {
           log(OWNER_HUNTER, VERB_DECODED, data.logId());
         }
         stats.dispatchBitmapDecoded(bitmap);
         //图片变换
         if (data.needsTransformation() || exifRotation != 0) {
           synchronized (DECODE_LOCK) {
             if (data.needsMatrixTransform() || exifRotation != 0) {
               bitmap = transformResult(data, bitmap, exifRotation);
               if (picasso.loggingEnabled) {
                 log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId());
               }
             }
             if (data.hasCustomTransformations()) {
               bitmap = applyCustomTransformations(data.transformations, bitmap);
               if (picasso.loggingEnabled) {
                 log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId(), "from custom transformations");
               }
             }
           }
           if (bitmap != null) {
             stats.dispatchBitmapTransformed(bitmap);
           }
         }
       }
    
       return bitmap;
     }
    
    • 缓存里面找
    • 没找到调用Handlerload方法了
    • load拿到结果取出 bitmap
    • 查看我们是不是要变化即data.needsTransformation,如果要变化就变化
    • 最后返回bitmapHunter ,调用dispatcher.dispatchComplete(this)
    void performComplete(BitmapHunter hunter) {
        if (shouldWriteToMemoryCache(hunter.getMemoryPolicy())) {
          cache.set(hunter.getKey(), hunter.getResult());
        }
        hunterMap.remove(hunter.getKey());
        batch(hunter);
        if (hunter.getPicasso().loggingEnabled) {
          log(OWNER_DISPATCHER, VERB_BATCHED, getLogIdsForHunter(hunter), "for completion");
        }
      }
    
    • 首先根据缓存策略看是不是缓存
    • 执行完后应该删除hunter在容器中
    • 批量处理hunter

    然后看看怎么批量处理的吧:

    batch = new ArrayList();
      private void batch(BitmapHunter hunter) {
        if (hunter.isCancelled()) {
          return;
        }
        if (hunter.result != null) {
          hunter.result.prepareToDraw();
        }
        batch.add(hunter);
        if (!handler.hasMessages(HUNTER_DELAY_NEXT_BATCH)) {
          handler.sendEmptyMessageDelayed(HUNTER_DELAY_NEXT_BATCH, BATCH_DELAY);
        }
      }
    

    看到这里BATCH_DELAY是200ms 意思说在这期间全部返回的结果都交给了batch这个容器,最后延迟200ms发送信息

    事情又回到了dispatcher的子线程中,而子线程会调用dispatcher.performComplete(hunter);

      void performBatchComplete() {
        List<BitmapHunter> copy = new ArrayList<BitmapHunter>(batch);
        batch.clear();
        mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(HUNTER_BATCH_COMPLETE, copy));
        logBatch(copy);
      }
    
    • 子线程提出批量的BitmapHunter然后清空batch
    • 最后交给主线程批量更新UI

    下面就看看主线程吧:

    case HUNTER_BATCH_COMPLETE: {
              @SuppressWarnings("unchecked") List<BitmapHunter> batch = (List<BitmapHunter>) msg.obj;
              //noinspection ForLoopReplaceableByForEach
              for (int i = 0, n = batch.size(); i < n; i++) {
                BitmapHunter hunter = batch.get(i);
                hunter.picasso.complete(hunter);
              }
    

    不用说逐个调用hunter.picasso.complete(hunter);

     @Override public void complete(Bitmap result, Picasso.LoadedFrom from) {
        Action single = hunter.getAction();
        List<Action> joined = hunter.getActions();
    
        boolean hasMultiple = joined != null && !joined.isEmpty();
        boolean shouldDeliver = single != null || hasMultiple;
    
        if (!shouldDeliver) {
          return;
        }
    
        Uri uri = hunter.getData().uri;
        Exception exception = hunter.getException();
        Bitmap result = hunter.getResult();
        LoadedFrom from = hunter.getLoadedFrom();
    
        if (single != null) {
          deliverAction(result, from, single, exception);
        }
    
        if (hasMultiple) {
          //noinspection ForLoopReplaceableByForEach
          for (int i = 0, n = joined.size(); i < n; i++) {
            Action join = joined.get(i);
            deliverAction(result, from, join, exception);
          }
        }
    
        if (listener != null && exception != null) {
          listener.onImageLoadFailed(this, uri, exception);
        }
      }
    

    那我们再开看看分发deliverAction方法吧

     private void deliverAction(Bitmap result, LoadedFrom from, Action action, Exception e) {
        if (action.isCancelled()) {
          return;
        }
        if (!action.willReplay()) {
          targetToAction.remove(action.getTarget());
        }
        if (result != null) {
          if (from == null) {
            throw new AssertionError("LoadedFrom cannot be null.");
          }
          action.complete(result, from);
          if (loggingEnabled) {
            log(OWNER_MAIN, VERB_COMPLETED, action.request.logId(), "from " + from);
          }
        } else {
          action.error(e);
          if (loggingEnabled) {
            log(OWNER_MAIN, VERB_ERRORED, action.request.logId(), e.getMessage());
          }
        }
      }
    

    这里没什么要讲得只是解决前面的判断问题吗,继续轮到ImageViewAction. complete

    @Override public void complete(Bitmap result, Picasso.LoadedFrom from) {
      if (result == null) {
        throw new AssertionError(
            String.format("Attempted to complete action with no result!\n%s", this));
      }
    
      //得到target也就是ImageView
      ImageView target = this.target.get();
      if (target == null) {
        return;
      }
    
      Context context = picasso.context;
      boolean indicatorsEnabled = picasso.indicatorsEnabled;
      //通过PicassoDrawable来将bitmap设置到ImageView上
      PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);
    
      //回调callback接口
      if (callback != null) {
        callback.onSuccess();
      }
    }
    
    • 判断target很简单,因为他是弱引用,有个能target到达这里已经被回收了
    • PicassoDrawable.setBitmap方法吧bitmap设置给ImageView
    • 调用成功的回调
      特别说一下PicassoDrawable负责入场动画,但是这里不深入
      到这里所以的流程都结束了

    我们需要简化总接一下流程即:

    创建->入队->执行->解码->变换->批处理->完成->分发->显示(可选)

    • 创建:get()初始化配置,创建picassio,调用load()创建RequestCreater
    • 入队:在into中,RequestCreater创建request,通过request创建一个 Action即 一个完整的任务,交给picasso最后传给dispatcher的子线程,子线程找到对应的ReqestHandler,并打包Action 传给Hunter,最后把Hunter放入线程池入队
    • 解码: 在线程池中,调用ReqestHandlerload方法尝试解码Action
    • 变换: 拿到解码后的结果后判断是不是需要变换,如果需要就进行变化
    • 批处理 :将变换后的结果放入容器batch中,每隔0.2秒线程池就发送给dispatcher的子线程信息,子线程接收到信息后取出batch容器内容,并把它发送给主线程,主线程接受到对象逐个处理容器中每个hunter返回的结果
    • 完成: 上面就会调用picasso.complete(hunter)方法:代表任务执行完成
    • 分发: complete判断是不是需要分发如果需要就调用deliverAction(result, from, join);方法
    • 显示 : 上面任务就会调用action.complete(result, from); 根据action的不同调用对饮的显示方法

    设计模式

    建造者模式

    建造者模式是指:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式应该是我们都比较熟悉的一种模式,在创建AlertDialog的时候通过配置不同的参数就可以展示不同的AlertDialog,这也正是建造者模式的用途,通过不同的参数配置或者不同的执行顺序来构建不同的对象,在Picasso里当构建RequestCreator的时候正是使用了这种设计模式,我们通过可选的配置比如centerInside(),placeholder()等等来分别达到不同的使用方式,在这种使用场景下使用建造者模式是非常合适的.

    责任链模式

    责任链模式是指:一个请求沿着一条“链”传递,直到该“链”上的某个处理者处理它为止。当我们有一个请求可以被多个处理者处理或处理者未明确指定时。可以选择使用责任链模式,在Picasso里当我们通过BitmapHunter的forRequest()方法构建一个BitmapHunter对象时,需要为Request指定一个对应的RequestHandler来进行处理Request.这里就使用了责任链模式,依次调用requestHandler.canHandleRequest(request)方法来判断是否该RequestHandler能处理该Request如果可以就构建一个RequestHandler对象返回.这里就是典型的责任链思想的体现。

    引用:Picasso源代码分析

    相关文章

      网友评论

          本文标题:Picassio源码分析

          本文链接:https://www.haomeiwen.com/subject/vgiggftx.html