美文网首页
Picasso加载一张图片

Picasso加载一张图片

作者: _Ryan | 来源:发表于2018-11-07 21:05 被阅读6次

    目录

    Picasso加载一张图片的流程

    • 创建

      //通过定义一个PicassoProvider来获取Context
      //单例创建Picasso实例  
      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;
        }
      
      //在AndroidManifest.xml中声明
      @RestrictTo(LIBRARY)
      public final class PicassoProvider extends ContentProvider {
      
        @SuppressLint("StaticFieldLeak") static Context context;
      
        @Override public boolean onCreate() {
          context = getContext();
          return true;
        }
      }
      
    aaaa.png

    build( ) 创建Picasso实例

    /** Create the {@link Picasso} instance. */
    public Picasso build() {
      Context context = this.context;
    
      //创建默认下载器
      if (downloader == null) {
        downloader = new OkHttp3Downloader(context);
      }
      
      //创建LRU内存缓存
      if (cache == null) {
        cache = new LruCache(context);
      }
      
      //创建线程池,默认有3个执行线程
      if (service == null) {
        service = new PicassoExecutorService();
      }
      
      //创建默认transformer
      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);
    }
    
    //Picasso构造方法 对象赋值&创建一个新对象
    //最主要的是初始化了allRequestHandlers 除了自定义的extraRequestHandlers  添加了7个默认的RequestHandler
    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);
    
      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);
      //省略...
    }
    
    public abstract class RequestHandler {
      
      //来判断当前类型的RequestHandler能否处理request
      public abstract boolean canHandleRequest(Request data);
      
      //使用传入的requst来加载图片,加载的结果放入Result中返回
      @Nullable
      public abstract Result load(Request request, int networkPolicy) throws IOException;
    
      //待定
      int getRetryCount() {
        return 0;
      }
    
      //待定
      boolean shouldRetry(boolean airplaneMode, NetworkInfo info) {
        return false;
      }
    
      //待定
      boolean supportsReplay() {
        return false;
      }
    }
    

    创建好Picasso实例后,便是load了

    //load的几个重载方法最后都会来调用参数为Uri的方法 生成一个RequestCreator,
    //来执行接下来的trannform() rotate() into()等操作
    public RequestCreator load(@Nullable Uri uri) {
      return new RequestCreator(this, uri, 0);
    }
    
    • 入队

      //通过构造方法传入一个Picasso实例的引用,并且创建一个Request.Builder()的实例
      //为创建一个Request做准备
      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);
      }
      

      将我们需要加载的图片的信息都保存在data里面,我们设置centerCrop( )或者transform( )实际上都是对data内对应的变量标识进行设置,然后在into( )中进行build 生成一个Request,

      然后看一下into( )方法的实现

      public void into(ImageView target, Callback callback) {
        long started = System.nanoTime();
        //检查是否在主线程
        checkMain();
      
        if (target == null) {
          throw new IllegalArgumentException("Target must not be null.");
        }
      
        //如果没有设置要加载的图片的Uri或者resourceId,直接设置占位图然后返回
        if (!data.hasImage()) {
          picasso.cancelRequest(target);
          if (setPlaceholder) {
            setPlaceholder(target, getPlaceholderDrawable());
          }
          return;
        }
      
        //是否延时加载,也就是选择fit()模式
        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());
            }
            //监听ImageView的ViewTreeObserver.OnPreDrawListener接口,一旦ImageView
            //的宽高被赋值,就按照ImageView的宽高继续加载.
            picasso.defer(target, new DeferredRequestCreator(this, target, callback));
            return;
          }
          data.resize(width, height);
        }
      
        //构建request
        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;
          }
        }
      
        //缓存中没有,先设置占位图,然后构建一个ImageViewAction
        if (setPlaceholder) {
          setPlaceholder(target, getPlaceholderDrawable());
        }
        //Action的实现类保存了这次加载需要的所有信息,还提供了加载完成后的回调方法
        Action action =
            new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,
                errorDrawable, requestKey, tag, callback, noFade);
        
        //将Action对象提交到队列
        picasso.enqueueAndSubmit(action);
      }
      
      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);
        }
        
        //提交Action 最后转到Dispatcher类的 dispatchSubmit方法
        submit(action);
      }
      
      void submit(Action action) {
        dispatcher.dispatchSubmit(action);
      }
      
      //Dispatcher类的dispatchXXX系列方法都是通过一个Handler来发送消息
      

      看一下Dispatcher的主要实现

      Dispatcher(Context context, ExecutorService service, Handler mainThreadHandler,
          Downloader downloader, Cache cache, Stats stats) {
        this.dispatcherThread = new DispatcherThread();
        this.dispatcherThread.start();    
        this.handler = new DispatcherHandler(dispatcherThread.getLooper(), this);
        this.mainThreadHandler = mainThreadHandler;
      }
      
        void dispatchSubmit(Action action) {
          handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action));
        }
      
        static class DispatcherThread extends HandlerThread {
        DispatcherThread() {
          super(Utils.THREAD_PREFIX + DISPATCHER_THREAD_NAME, THREAD_PRIORITY_BACKGROUND);
        }
      }
      
        private static class DispatcherHandler extends Handler {
          private final Dispatcher dispatcher;
      
          DispatcherHandler(Looper looper, Dispatcher dispatcher) {
            super(looper);
            this.dispatcher = dispatcher;
          }
      
          @Override public void handleMessage(final Message msg) {
            switch (msg.what) {
              case REQUEST_SUBMIT: {
                Action action = (Action) msg.obj;
                dispatcher.performSubmit(action);
                break;
                //省略...
              }
            }
          }
      

      首先自己创建了一个DispatcherThread子线程,然后创建了DispatcherHandler对象,用这个Handler来进行发送消息,而在DispatcherHandler的handleMessage中,最终调用了dispatcher.performXXX(action);等方法

    • 执行、解码、变化

      来看一下performSubmit( )方法的实现

        void performSubmit(Action action, boolean dismissFailed) {
          //如果pausedActions包含这个Action,则暂停
          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;
          }
      
          //此Action对应的hunter存在,attach后直接返回
          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对象 实现了Runnable接口
          hunter = forRequest(action.getPicasso(), this, cache, stats, action);
          //通过ExecutorService执行hunter,并返回future对象。
          //提交线程池执行
          hunter.future = service.submit(hunter);
          //将构造好的hunter对象加入到hunterMap缓存起来
          hunterMap.put(action.getKey(), hunter);
          if (dismissFailed) {
            failedActions.remove(action.getTarget());
          }
          if (action.getPicasso().loggingEnabled) {
            log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
          }
        }
      
        static BitmapHunter forRequest(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats,
            Action action) {
          Request request = action.getRequest();
          List<RequestHandler> requestHandlers = picasso.getRequestHandlers();
      
          //通过遍历所有的requestHandlers(包括自定的和默认添加的那7个)寻找能处理这个Request的requestHandler
          //使用这个requestHandler来构建BitmapHunter
          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);
        }
      
      //BitmapHunter实现了Runable接口,并且通过ExecutorService来执行,接下来就看一下BitmapHunter的run( )方法
      @Override
      public void run() {
        try {
          updateThreadName(data);
      
          if (picasso.loggingEnabled) {
            log(OWNER_HUNTER, VERB_EXECUTING, getLogIdsForHunter(this));
          }
      
          //调用hunt()方法并且返回一个Bitmap对象
          result = hunt();
      
          //然后根绝结果调用Dispatcher的dispatchXXX系列方法来发送不同的消息
          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);
        }
      }
      
      /**
       * Global lock for bitmap decoding to ensure that we are only decoding one at a time. Since
       * this will only ever happen in background threads we help avoid excessive memory thrashing as
       * well as potential OOMs. Shamelessly stolen from Volley.
       */
      private static final Object DECODE_LOCK = new Object();
      
      //hunter方法
      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;
          }
        }
      
        networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy;
        //调用requestHandler的load方法得到一个result
        //load方法在不同的requestHandler中有不同的实现
        //(解码)
        RequestHandler.Result result = requestHandler.load(data, networkPolicy);
        if (result != null) {
          loadedFrom = result.getLoadedFrom();
          exifOrientation = result.getExifOrientation();
          bitmap = result.getBitmap();
      
          // If there was no Bitmap then we need to decode it from the stream.
          if (bitmap == null) {
            Source source = result.getSource();
            try {
              bitmap = decodeStream(source, data);
            } finally {
              try {
                //noinspection ConstantConditions If bitmap is null then source is guranteed non-null.
                source.close();
              } catch (IOException ignored) {
              }
            }
          }
        }
      
        if (bitmap != null) {
          if (picasso.loggingEnabled) {
            log(OWNER_HUNTER, VERB_DECODED, data.logId());
          }
          stats.dispatchBitmapDecoded(bitmap);
          //处理Transformation(变化)
          if (data.needsTransformation() || exifOrientation != 0) {
            //图片在转化的时候需要一片临时内存,加全局锁解决瞬时OOOM的问题
            //或者使用synchronized(BitmapHunter.class){}
            synchronized (DECODE_LOCK) {
              if (data.needsMatrixTransform() || exifOrientation != 0) {
                bitmap = transformResult(data, bitmap, exifOrientation);
                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);
            }
          }
        }
      
        //返回Bitmap
        return bitmap;
      }
      

      最后拿到result之后,会调用dispatcher.dispatchComplete(this),最终会调用dispatcher.performComplete()方法

    • 批处理

        void performComplete(BitmapHunter hunter) {
          //是否加入缓存
          if (shouldWriteToMemoryCache(hunter.getMemoryPolicy())) {
            cache.set(hunter.getKey(), hunter.getResult());
          }
          //完成后hunterMap中移除
          hunterMap.remove(hunter.getKey());
          batch(hunter);
          if (hunter.getPicasso().loggingEnabled) {
            log(OWNER_DISPATCHER, VERB_BATCHED, getLogIdsForHunter(hunter), "for completion");
          }
        }
      
        //批处理
        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中调用performBatchComplete
            handler.sendEmptyMessageDelayed(HUNTER_DELAY_NEXT_BATCH, BATCH_DELAY);
          }
        }
      
        void performBatchComplete() {
          List<BitmapHunter> copy = new ArrayList<>(batch);
          batch.clear();
          //消息发动到主线程进行处理
          mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(HUNTER_BATCH_COMPLETE, copy));
          logBatch(copy);
        }
      
      //mainThreadHandler中
      //...
      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);
                //调用Picasso#complete方法
                hunter.picasso.complete(hunter);
              }
              break;
            }
      //...
      
    • 完成、分发

      接着看一下Picasso#complete( )方法的实现

        void complete(BitmapHunter hunter) {
          //获取执行的那个Action
          Action single = hunter.getAction();
          //获取被添加进来的Action
          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的实现
        //此方法的主要实现就是回调Action的complete方法或者error方法
        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());
            }
          }
        }
      
    • 显示

      之前分析是看到,这个加载流程这里的Action是ImageViewAction,下面看一下ImageViewAction对应的实现

      @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));
        }
      
        //获取要显示的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);
      
        if (callback != null) {
          callback.onSuccess();
        }
      }
      //使用PicassoDrawable来设置Bitmap,主要是为了设置渐变的加载动画
      
    • PicassoDrawable渐变动画

       PicassoDrawable(Context context, Bitmap bitmap, Drawable placeholder,
            Picasso.LoadedFrom loadedFrom, boolean noFade, boolean debugging) {
          super(context.getResources(), bitmap);
      
          this.debugging = debugging;
          this.density = context.getResources().getDisplayMetrics().density;
      
          this.loadedFrom = loadedFrom;
      
         //noFade为false,并且不是从内存中加载的时候,才会有渐变动画
          boolean fade = loadedFrom != MEMORY && !noFade;
          if (fade) {
            this.placeholder = placeholder;
            animating = true;
            startTimeMillis = SystemClock.uptimeMillis();
          }
        }
      
        @Override public void draw(Canvas canvas) {
          if (!animating) {
            super.draw(canvas);
          } else {
            float normalized = (SystemClock.uptimeMillis() - startTimeMillis) / FADE_DURATION;
            if (normalized >= 1f) {
              animating = false;
              placeholder = null;
              super.draw(canvas);
            } else {
              if (placeholder != null) {
                placeholder.draw(canvas);
              }
      
              //渐变动画
              // setAlpha will call invalidateSelf and drive the animation.
              int partialAlpha = (int) (alpha * normalized);
              super.setAlpha(partialAlpha);
              super.draw(canvas);
              super.setAlpha(alpha);
            }
          }
      
          if (debugging) {
            drawDebugIndicator(canvas);
          }
        }
      

    相关文章

      网友评论

          本文标题:Picasso加载一张图片

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