Request
Request是图片请求,声明所请求的Bitmap的信息,比如Uri,资源id,目标宽高等等。Request采用Builder模式来创建,定义了内部类Request.Builder。
public final class Request {
// Request的id,由AtomicInteger生成。
int id;
// 该请求第一次被提交的时间
long started;
// 网络策略
int networkPolicy;
// 图片的Uri
public final Uri uri;
// 图片的资源id,Uri和资源id两者只能选其一。
public final int resourceId;
// 替代Uri或资源id作为缓存时的key,该值相同则被认为是相同的Request。
public final String stableKey;
// 自定义的Transformation
public final List<Transformation> transformations;
// 给Bitmap设定的宽度
public final int targetWidth;
// 给Bitmap设定的高度
public final int targetHeight;
// scaleType是否为centerCrop
public final boolean centerCrop;
// scaleType是否为centerInside,centerInside和centerCrop只有一个为true。
public final boolean centerInside;
// 是否只是缩小图片
public final boolean onlyScaleDown;
// 旋转角度
public final float rotationDegrees;
// 旋转轴的X坐标
public final float rotationPivotX;
// 旋转轴的Y坐标
public final float rotationPivotY;
// 是否有旋转轴
public final boolean hasRotationPivot;
// Bitmap的Config
public final Bitmap.Config config;
// 优先级
public final Priority priority;
}
Target
Target是图片加载的监听器。因为框架内部存储的原因,必须正确实现equals和hashCode方法。 当在Adapter中使用时,Target的实例会被比较进而判断是否正在回收View。为了保证ListView等的View回收机制能够正常运行,使用Adapter时推荐自定义View实现该接口。
public interface Target {
// Bitmap成功加载时被回调,此处不能回收Bitmap。
void onBitmapLoaded(Bitmap bitmap, LoadedFrom from);
// Bitmap加载失败时被回调。
void onBitmapFailed(Drawable errorDrawable);
// Request被提交前被回调。
void onPrepareLoad(Drawable placeHolderDrawable);
}
Action
Action是一个抽象类,有两个抽象方法。
abstract class Action<T> {
// 定义了弱引用来保持ImageView,RemoteViews等,避免内存泄漏
static class RequestWeakReference<M> extends WeakReference<M> {
final Action action;
public RequestWeakReference(Action action, M referent, ReferenceQueue<? super M> q) {
super(referent, q);
this.action = action;
}
}
// 保持了对Request的引用
final Request request;
// 保持了对Target/ImageView/RemoteViews的弱引用。
final WeakReference<T> target;
// 成功获取Bitmap时被回调
abstract void complete(Bitmap result, Picasso.LoadedFrom from);
// Bitmap获取失败时被回调
abstract void error();
}
Action的实现类有GetAction、FetchAction、ImageViewAction、RemoteViewsAction、NotificationAction和TargetAction。
RequestCreator
调用Picasso的load(Uri)或者load(String)方法可以获取RequestCreator对象。 RequestCreator提供了一系列的方法比如placeholder/error/tag等来设置Request.Builder,然后通过createRequest方法创建Request。 RequestCreator还提供一系列的方法来创建Action。
private Request createRequest(long started) {
int id = nextId.getAndIncrement();
// 通过Request.Buidler创建Requst,并设置id和started。
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());
}
// 如果Picasso设置了RequestTransformer,则对Request做转化。
Request transformed = picasso.transformRequest(request);
if (transformed != request) {
// 如果Request被转化了,则给新Request并设置id和started。
transformed.id = id;
transformed.started = started;
if (loggingEnabled) {
log(OWNER_MAIN, VERB_CHANGED, transformed.logId(), "into " + transformed);
}
}
return transformed;
}
GetAction
// 同步获取Bitmap,不能在主线程中调用该方法。
// 获取的Bitmap不会被缓存在内存中,因为Cache的实现不能保证是同步的。
public Bitmap get() throws IOException {
long started = System.nanoTime();
// 确保不是在主线程
checkNotMain();
if (deferred) {
throw new IllegalStateException("Fit cannot be used with get.");
}
// 如果Uri或者资源id不存在,返回空。
if (!data.hasImage()) {
return null;
}
// 创建Request
Request finalData = createRequest(started);
String key = createKey(finalData, new StringBuilder());
// 创建GetAction,forRequest创建出BitmapHunter,调用其hunt方法,同步获取Bitmap。
Action action = new GetAction(picasso, finalData, memoryPolicy, networkPolicy, tag, key);
return forRequest(picasso, picasso.dispatcher, picasso.cache, picasso.stats, action).hunt();
}
// 因为GetAction是同步获取Bitmap,所以它的泛型是Void,抽象方法的实现都是为空。
class GetAction extends Action<Void> {
GetAction(Picasso picasso, Request data, int memoryPolicy, int networkPolicy, Object tag,
String key) {
super(picasso, null, data, memoryPolicy, networkPolicy, 0, null, key, tag, false);
}
@Override void complete(Bitmap result, Picasso.LoadedFrom from) {
}
@Override public void error() {
}
}
FetchAction
// 异步获取Bitmap,然后回调Callback方法。 该方法可以用来预先给内存缓存添加图片。
// callback是强引用,在获取到Bitmap前,Activity和Fragment不能被垃圾回收。
public void fetch(Callback callback) {
long started = System.nanoTime();
if (deferred) {
throw new IllegalStateException("Fit cannot be used with fetch.");
}
if (data.hasImage()) {
// Request的priority默认是LOW。
if (!data.hasPriority()) {
data.priority(Priority.LOW);
}
//创建Request
Request request = createRequest(started);
String key = createKey(request, new StringBuilder());
// 根据Request得出的key查找内存缓存
Bitmap bitmap = picasso.quickMemoryCacheCheck(key);
// 如果内存不为空则回调Callback方法。
if (bitmap != null) {
if (picasso.loggingEnabled) {
log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY);
}
if (callback != null) {
callback.onSuccess();
}
} else {
// 如果内存没有,则创建FetchAction,提交到线程池执行。
Action action =
new FetchAction(picasso, request, memoryPolicy, networkPolicy, tag, key, callback);
picasso.submit(action);
}
}
}
// 简单的回调方法。
public interface Callback {
void onSuccess();
void onError();
public static class EmptyCallback implements Callback {
@Override public void onSuccess() {
}
@Override public void onError() {
}
}
}
// FetchAction在抽象方法中回调Callback方法。
// FetchAction的泛型是Object。
class FetchAction extends Action<Object> {
private final Object target;
private Callback callback;
FetchAction(Picasso picasso, Request data, int memoryPolicy, int networkPolicy, Object tag,
String key, Callback callback) {
// 因为target是普通的Object,而不是ImageView等会涉及Activity的内存回收,
// 此处的target不像父类那样保存成弱引用。
// 父类构造器的target为null。
super(picasso, null, data, memoryPolicy, networkPolicy, 0, null, key, tag, false);
// 把target保存到成员变量target。
this.target = new Object();
this.callback = callback;
}
@Override void complete(Bitmap result, Picasso.LoadedFrom from) {
if (callback != null) {
callback.onSuccess();
}
}
@Override void error() {
if (callback != null) {
callback.onError();
}
}
@Override void cancel() {
super.cancel();
// callback置为空,释放内存,以便系统回收Activity和Fragment。
callback = null;
}
@Override Object getTarget() {
// 返回target。
return target;
}
}
ImageViewAction
// 异步请求Bitmap,加载到ImageView中,并回调Callback方法。
// ImageView被保存为弱引用,但是Callback是强引用,会阻止Activity和Fragment被回收,记得调用cancel方法取消请求。
public void into(ImageView target, Callback callback) {
long started = System.nanoTime();
// 在主线程中调用该方法。
checkMain();
if (target == null) {
throw new IllegalArgumentException("Target must not be null.");
}
// 如果Uri或者资源id不存在,则取消ImageView的其他请求,显示预加载图片。
if (!data.hasImage()) {
picasso.cancelRequest(target);
if (setPlaceholder) {
setPlaceholder(target, getPlaceholderDrawable());
}
return;
}
// 如果Bitmap要按照ImageView的宽高来显示
if (deferred) {
if (data.hasSize()) {
throw new IllegalStateException("Fit cannot be used with resize.");
}
int width = target.getWidth();
int height = target.getHeight();
// 如果ImageView的宽高都不知道,则交给Picasso的defer延迟处理。
if (width == 0 || height == 0) {
if (setPlaceholder) {
setPlaceholder(target, getPlaceholderDrawable());
}
picasso.defer(target, new DeferredRequestCreator(this, target, callback));
return;
}
// 否则把Request的宽高设为ImageView的宽高。
data.resize(width, height);
}
// 创建Request
Request request = createRequest(started);
String requestKey = createKey(request);
// 如果允许从内存缓存中读取
if (shouldReadFromMemoryCache(memoryPolicy)) {
Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
if (bitmap != null) {
// 内存缓存读取成功,取消ImageView的其他请求,显示Bitmap,回调Callback方法。
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());
}
// 创建ImageViewAction,提交到线程池中执行。
Action action =
new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,
errorDrawable, requestKey, tag, callback, noFade);
picasso.enqueueAndSubmit(action);
}
// 把获取吃的Bitmap转化成PicassoDrawable,加载到ImageView中,并回调Callback方法。
class ImageViewAction extends Action<ImageView> {
Callback callback;
ImageViewAction(Picasso picasso, ImageView imageView, Request data, int memoryPolicy,
int networkPolicy, int errorResId, Drawable errorDrawable, String key, Object tag,
Callback callback, boolean noFade) {
super(picasso, imageView, data, memoryPolicy, networkPolicy, errorResId, errorDrawable, key,
tag, noFade);
this.callback = callback;
}
@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 target = this.target.get();
if (target == null) {
return;
}
Context context = picasso.context;
boolean indicatorsEnabled = picasso.indicatorsEnabled;
PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);
if (callback != null) {
callback.onSuccess();
}
}
@Override public void error() {
ImageView target = this.target.get();
if (target == null) {
return;
}
if (errorResId != 0) {
target.setImageResource(errorResId);
} else if (errorDrawable != null) {
target.setImageDrawable(errorDrawable);
}
if (callback != null) {
callback.onError();
}
}
@Override void cancel() {
super.cancel();
if (callback != null) {
callback = null;
}
}
}
TargetAction
// 异步请求Bitmap,然后回调Target的方法。
// 当使用实现Target接口的自定义View或者Adapter的ViewHolder,使用该方法。
public void into(Target target) {
long started = System.nanoTime();
// 在主线程中调用该方法。
checkMain();
if (target == null) {
throw new IllegalArgumentException("Target must not be null.");
}
if (deferred) {
throw new IllegalStateException("Fit cannot be used with a Target.");
}
// 如果Uri或者资源id为空时,取消Target已有的请求,然后显示预加载的图片。
if (!data.hasImage()) {
picasso.cancelRequest(target);
target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null);
return;
}
// 创建Request。
Request request = createRequest(started);
String requestKey = createKey(request);
// 如果运行读取内存缓存。
if (shouldReadFromMemoryCache(memoryPolicy)) {
Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
if (bitmap != null) {
// 内存缓存读取成功,取消Target上已有的请求,回调Target方法。
picasso.cancelRequest(target);
target.onBitmapLoaded(bitmap, MEMORY);
return;
}
}
// 显示预加载的图片
target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null);
// 创建TargetAction,提交到线程池中执行。
Action action =
new TargetAction(picasso, target, request, memoryPolicy, networkPolicy, errorDrawable,
requestKey, tag, errorResId);
picasso.enqueueAndSubmit(action);
}
// TargetAction的泛型是Target
final class TargetAction extends Action<Target> {
TargetAction(Picasso picasso, Target target, Request data, int memoryPolicy, int networkPolicy,
Drawable errorDrawable, String key, Object tag, int errorResId) {
super(picasso, target, data, memoryPolicy, networkPolicy, errorResId, errorDrawable, key, tag,
false);
}
@Override 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 target = getTarget();
if (target != null) {
target.onBitmapLoaded(result, from);
if (result.isRecycled()) {
throw new IllegalStateException("Target callback must not recycle bitmap!");
}
}
}
@Override void error() {
Target target = getTarget();
if (target != null) {
if (errorResId != 0) {
target.onBitmapFailed(picasso.context.getResources().getDrawable(errorResId));
} else {
target.onBitmapFailed(errorDrawable);
}
}
}
}
RemoteViewsAction
// 异步加载Bitmamp到Notification中
public void into(RemoteViews remoteViews, int viewId, int notificationId,
Notification notification) {
long started = System.nanoTime();
if (remoteViews == null) {
throw new IllegalArgumentException("RemoteViews must not be null.");
}
if (notification == null) {
throw new IllegalArgumentException("Notification must not be null.");
}
if (deferred) {
throw new IllegalStateException("Fit cannot be used with RemoteViews.");
}
if (placeholderDrawable != null || placeholderResId != 0 || errorDrawable != null) {
throw new IllegalArgumentException(
"Cannot use placeholder or error drawables with remote views.");
}
// 创建Request
Request request = createRequest(started);
String key = createKey(request, new StringBuilder()); // Non-main thread needs own builder.
// 创建RemoteViewsAction
RemoteViewsAction action =
new NotificationAction(picasso, request, remoteViews, viewId, notificationId, notification,
memoryPolicy, networkPolicy, key, tag, errorResId);
performRemoteViewInto(action);
}
// 异步加载Bitmamp到Widget中
public void into(RemoteViews remoteViews, int viewId, int[] appWidgetIds) {
long started = System.nanoTime();
if (remoteViews == null) {
throw new IllegalArgumentException("remoteViews must not be null.");
}
if (appWidgetIds == null) {
throw new IllegalArgumentException("appWidgetIds must not be null.");
}
if (deferred) {
throw new IllegalStateException("Fit cannot be used with remote views.");
}
if (placeholderDrawable != null || placeholderResId != 0 || errorDrawable != null) {
throw new IllegalArgumentException(
"Cannot use placeholder or error drawables with remote views.");
}
// 创建Request
Request request = createRequest(started);
String key = createKey(request, new StringBuilder()); // Non-main thread needs own builder.
// 创建AppWidgetAction
RemoteViewsAction action =
new AppWidgetAction(picasso, request, remoteViews, viewId, appWidgetIds, memoryPolicy,
networkPolicy, key, tag, errorResId);
performRemoteViewInto(action);
}
private void performRemoteViewInto(RemoteViewsAction action) {
// 如果允许读取内存缓存
if (shouldReadFromMemoryCache(memoryPolicy)) {
Bitmap bitmap = picasso.quickMemoryCacheCheck(action.getKey());
// 如果内存缓存读取成功,则调用RemoteViewsAction的complete方法。
if (bitmap != null) {
action.complete(bitmap, MEMORY);
return;
}
}
if (placeholderResId != 0) {
action.setImageResource(placeholderResId);
}
// 否则交给线程池处理
picasso.enqueueAndSubmit(action);
}
// RemoteViewsAction的泛型是RemoteViewsTarget
abstract class RemoteViewsAction extends Action<RemoteViewsAction.RemoteViewsTarget> {
final RemoteViews remoteViews;
final int viewId;
private RemoteViewsTarget target;
RemoteViewsAction(Picasso picasso, Request data, RemoteViews remoteViews, int viewId,
int errorResId, int memoryPolicy, int networkPolicy, Object tag, String key) {
super(picasso, null, data, memoryPolicy, networkPolicy, errorResId, null, key, tag, false);
this.remoteViews = remoteViews;
this.viewId = viewId;
}
@Override void complete(Bitmap result, Picasso.LoadedFrom from) {
remoteViews.setImageViewBitmap(viewId, result);
update();
}
@Override public void error() {
if (errorResId != 0) {
setImageResource(errorResId);
}
}
@Override RemoteViewsTarget getTarget() {
if (target == null) {
target = new RemoteViewsTarget(remoteViews, viewId);
}
return target;
}
void setImageResource(int resId) {
remoteViews.setImageViewResource(viewId, resId);
update();
}
abstract void update();
static class RemoteViewsTarget {
final RemoteViews remoteViews;
final int viewId;
RemoteViewsTarget(RemoteViews remoteViews, int viewId) {
this.remoteViews = remoteViews;
this.viewId = viewId;
}
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RemoteViewsTarget remoteViewsTarget = (RemoteViewsTarget) o;
return viewId == remoteViewsTarget.viewId && remoteViews.equals(
remoteViewsTarget.remoteViews);
}
@Override public int hashCode() {
return 31 * remoteViews.hashCode() + viewId;
}
}
static class AppWidgetAction extends RemoteViewsAction {
private final int[] appWidgetIds;
AppWidgetAction(Picasso picasso, Request data, RemoteViews remoteViews, int viewId,
int[] appWidgetIds, int memoryPolicy, int networkPolicy, String key, Object tag,
int errorResId) {
super(picasso, data, remoteViews, viewId, errorResId, memoryPolicy, networkPolicy, tag, key);
this.appWidgetIds = appWidgetIds;
}
@Override void update() {
AppWidgetManager manager = AppWidgetManager.getInstance(picasso.context);
manager.updateAppWidget(appWidgetIds, remoteViews);
}
}
static class NotificationAction extends RemoteViewsAction {
private final int notificationId;
private final Notification notification;
NotificationAction(Picasso picasso, Request data, RemoteViews remoteViews, int viewId,
int notificationId, Notification notification, int memoryPolicy, int networkPolicy,
String key, Object tag, int errorResId) {
super(picasso, data, remoteViews, viewId, errorResId, memoryPolicy, networkPolicy, tag, key);
this.notificationId = notificationId;
this.notification = notification;
}
@Override void update() {
NotificationManager manager = getService(picasso.context, NOTIFICATION_SERVICE);
manager.notify(notificationId, notification);
}
}
}
DeferredRequestCreator
如果想把Bitmap加载到ImageView中,且Bitmap按照ImageView的宽高来显示,需要调用RequestCreator的fit()方法。该方法把RequestCreator封装成DeferredRequestCreator。DeferredRequestCreator会监听ImageView的绘制,获取到其具体宽高后再通过RequestCreator请求图片。
// DeferredRequestedCreator实现了ViewTreeObserver.OnPreDrawListener接口,来获取ImageView的宽高。
class DeferredRequestCreator implements ViewTreeObserver.OnPreDrawListener {
final RequestCreator creator;
final WeakReference<ImageView> target;
Callback callback;
DeferredRequestCreator(RequestCreator creator, ImageView target, Callback callback) {
this.creator = creator;
this.target = new WeakReference<ImageView>(target);
this.callback = callback;
// 注册监听器
target.getViewTreeObserver().addOnPreDrawListener(this);
}
@Override public boolean onPreDraw() {
ImageView target = this.target.get();
if (target == null) {
return true;
}
ViewTreeObserver vto = target.getViewTreeObserver();
if (!vto.isAlive()) {
return true;
}
int width = target.getWidth();
int height = target.getHeight();
if (width <= 0 || height <= 0) {
return true;
}
// 获取其宽高后移除监听器
vto.removeOnPreDrawListener(this);
// 把Reqeust的宽高设置成ImageView的宽高,然后调用RequestCreator的into方法请求Bitmap
this.creator.unfit().resize(width, height).into(target, callback);
return true;
}
// 取消请求时,Callback置为空,同时移除监听器
void cancel() {
callback = null;
ImageView target = this.target.get();
if (target == null) {
return;
}
ViewTreeObserver vto = target.getViewTreeObserver();
if (!vto.isAlive()) {
return;
}
vto.removeOnPreDrawListener(this);
}
}