Picasso(四into设置图片方法解析)

Picasso(四into设置图片方法解析)

这就是具体的设置图片的操作

public void into (ImageView target, Callback callback){
        long started = System.nanoTime();
        // 通过当前的Looper来判断是否在主线程
        checkMain();
        // 当前的ImageView不能为空
        if (target == null) {
            throw new IllegalArgumentException("Target must not be null.");
        }

        // 通过uri或者资源id判断,如果没有图片信息就取消当前的请求,并设置占位图片
        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);
        }

        // 这里主要是如果之前自定义了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);
    }

其中的cancelRequest方法回调用cancelExistingRequest(Action就在这里简单说明一下,其实它就是request的包装类,还包括Picasso对象,缓存策略等)

void cancelExistingRequest(Object target) {
// 判断是否在主线程
checkMain();
// 这个map是将请求对象和请求关联起来(object 比如ImageView),移除请求对象
Action action = targetToAction.remove(target);
if (action != null) {
  // 同时移除请求
  action.cancel();
  // 通过dispatcher分发器,用子线程分发器的handler来取消请求(关于这个,在get方法中描述过)
  dispatcher.dispatchCancel(action);
}
if (target instanceof ImageView) {
  // 转换成需要的ImageView
  ImageView targetImageView = (ImageView) target;
  // DeferredRequestCreator其实就是RequestCreator的包装类,是为了对ImageView的
  //监听,跟进去,会发现getViewTreeObserver来监听,获取如具体的宽高等,因此也需要移除。
  DeferredRequestCreator deferredRequestCreator =
      targetToDeferredRequestCreator.remove(targetImageView);
  if (deferredRequestCreator != null) {
    deferredRequestCreator.cancel();
  }
}
}

以上用到了两个比较重要的类,BitmapHunter和Action,这里我们简单解释以下

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);
}
}

可以看到,在run方法中主要就是获取我们需要的Bitmap,通过dispatcher调用方法,在子线程中通过Handler来进行操作。这里我们需要理解的是,获取图片,以及获取成功后是否缓存,失败后怎么处理的一系列操作,这些都是通过Dispatcher中的handler来处理了的。

Action

这里就不再赘述了,就是request的包装类,其中包含了很多的其他东西,比如缓存策略,Picasso对象,等。

最后我们跟进去最后的提交任务

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);
}

这个方法就是object和action的校验检查。最后我们继续追踪,会发现又是通过dispatcher所在子线程的handler来进行处理,最后一直调用performSubmit方法

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);
// 交给线程池处理(获取图片),关注BitmapHunter的run方法(之前讲过了)
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());
}
}

当这一切都完成之后就可以设置图片,加载成功了。

总结

在这个方法中,我们需要理解和知道的是,我们首先进行一些判断,是否在主线程,object的空指针和匹配为题等,在一些健壮性判断完成之后,开始建立请求提交,submit,以及我们的一些标记和建立联系也都是贯穿建立的,也是通过分发handler来完成请求,从内存到网络,最后提交成功,完成显示。核心,就是任务的提交。

此次Picasso的感受:

这个设计非常nice的地方就是

1.通过构建者模式收集我们设置的属性,同时完成一些初始化,我们最后就可以通过Builder获取我们想要的属性。

2.同时也是其他框架的一些共同点,就是封装。确实这里面很多的封装类设计的非常好,比如Dispatcher,BitmapHunter,框架中非常突出的核心类。在传递的过程中,很精简,类中包括了我们要的信息,不需要过多的拆分,调用麻烦,或者不拆分,耦合严重。这是值得我们学习的。

2.同时也是最终要的,就是dispatcher和main的两个handler,整个框架都是通过handler来完成事件的分发和传递。也就说明,以后在我们的项目中Handler确实要善用,合理的分配。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值