您的位置:首页 > 其它

Picasso分析03

2015-10-03 00:03 483 查看

1 PicassoExecutorService

Exists as a custom type so that we can differentiate the use of defaults versus对抗 a user-supplied instance.


ThreadPoolExecutor构造函数的参数说明



class PicassoExecutorService extends ThreadPoolExecutor {
private static final int DEFAULT_THREAD_COUNT = 3;
PicassoExecutorService() {
super(DEFAULT_THREAD_COUNT, DEFAULT_THREAD_COUNT, 0, TimeUnit.MILLISECONDS,
new PriorityBlockingQueue<Runnable>(), new Utils.PicassoThreadFactory());
}
void adjustThreadCount(NetworkInfo info) {
if (info == null || !info.isConnectedOrConnecting()) {
setThreadCount(DEFAULT_THREAD_COUNT);
return;
}
switch (info.getType()) {
case ConnectivityManager.TYPE_WIFI:
case ConnectivityManager.TYPE_WIMAX:
case ConnectivityManager.TYPE_ETHERNET:
setThreadCount(4);
break;
case ConnectivityManager.TYPE_MOBILE:
switch (info.getSubtype()) {
case TelephonyManager.NETWORK_TYPE_LTE:  // 4G
case TelephonyManager.NETWORK_TYPE_HSPAP:
case TelephonyManager.NETWORK_TYPE_EHRPD:
setThreadCount(3);
break;
case TelephonyManager.NETWORK_TYPE_UMTS: // 3G
case TelephonyManager.NETWORK_TYPE_CDMA:
case TelephonyManager.NETWORK_TYPE_EVDO_0:
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
setThreadCount(2);
break;
case TelephonyManager.NETWORK_TYPE_GPRS: // 2G
case TelephonyManager.NETWORK_TYPE_EDGE:
setThreadCount(1);
break;
default:
setThreadCount(DEFAULT_THREAD_COUNT);
}
break;
default:
setThreadCount(DEFAULT_THREAD_COUNT);
}
}

private void setThreadCount(int threadCount) {
setCorePoolSize(threadCount);
setMaximumPoolSize(threadCount);
}

@Override
public Future<?> submit(Runnable task) {
PicassoFutureTask ftask = new PicassoFutureTask((BitmapHunter) task);
execute(ftask); // 看上面参数介绍的图片,要执行execute
return ftask; // 注意返回值啊,就是执行的ftask,可以返回这个因为RunnableFuture
}
// 1. class FutureTask<V> implements RunnableFuture<V>
// 2. interface RunnableFuture<V> extends Runnable, Future<V>
private static final class PicassoFutureTask extends FutureTask<BitmapHunter>
implements Comparable<PicassoFutureTask> {
private final PPBitmapHunter hunter;

public PicassoFutureTask(PPBitmapHunter hunter) {
super(hunter, null);
this.hunter = hunter;
}

@Override
public int compareTo(PicassoFutureTask other) {
Picasso.Priority p1 = hunter.getPriority();
Picasso.Priority p2 = other.hunter.getPriority();
// High-priority requests are "lesser" so they are sorted to the front.
// 优先级越高越靠前因为p2.ordinal() - p1.ordinal()
// Equal priorities are sorted by sequence number to provide FIFO ordering.
// ordinal()返回此枚举常量的序数0或1或2, name()返回此枚举常量的名字如LOW或HIGH等
return (p1 == p2 ? hunter.sequence - other.hunter.sequence : p2.ordinal() - p1.ordinal());
}
}
}


2 PicassoDrawable

可打印图片来源信息和渐变显示的Drawable



final class PicassoDrawable extends BitmapDrawable {
// Only accessed from main thread.
private static final Paint DEBUG_PAINT = new Paint();//debug paint
private static final float FADE_DURATION = 200f; //ms
// Create or update the drawable on the target ImageView to display the supplied bitmap image.
static void setBitmap(ImageView target, Context context, Bitmap bitmap,
Picasso.LoadedFrom loadedFrom, boolean noFade, boolean debugging) {
Drawable placeholder = target.getDrawable();//ImageView当前的drawable作为holder
if (placeholder instanceof AnimationDrawable) {
((AnimationDrawable) placeholder).stop(); // stop
}
PicassoDrawable drawable =
new PicassoDrawable(context, bitmap, placeholder, loadedFrom, noFade, debugging);
target.setImageDrawable(drawable);
}

// Create or update the drawable on the target {@link ImageView} to display the supplied
// placeholder image.
static void setPlaceholder(ImageView target, Drawable placeholderDrawable) {
target.setImageDrawable(placeholderDrawable);
if (target.getDrawable() instanceof AnimationDrawable) {
((AnimationDrawable) target.getDrawable()).start(); //start
}
}

private final boolean debugging;
private final float density;
private final Picasso.LoadedFrom loadedFrom;
Drawable placeholder;
long startTimeMillis;
boolean animating;
int alpha = 0xFF;

PicassoDrawable(Context context, Bitmap bitmap, Drawable placeholder,
Picasso.LoadedFrom loadedFrom, boolean noFade, boolean debugging) {
super(context.getResources(), bitmap);
this.debugging = debugging; // debug信息
this.density = context.getResources().getDisplayMetrics().density;
this.loadedFrom = loadedFrom;

boolean fade = loadedFrom != MEMORY && !noFade;//是从disk或network
if (fade) {
this.placeholder = placeholder;
animating = true; // true
startTimeMillis = SystemClock.uptimeMillis();
}
}

@Override public void draw(Canvas canvas) {
if (!animating) { // 是否需要fade
super.draw(canvas);
} else {
//uptimeMillis--Returns milliseconds since boot, not counting time spent in deep sleep.
float normalized = (SystemClock.uptimeMillis() - startTimeMillis) / FADE_DURATION;
if (normalized >= 1f) { //过了200ms
animating = false; // stop
placeholder = null;
super.draw(canvas);
} else { // 小于200ms
if (placeholder != null) {
placeholder.draw(canvas); //先画holder
}
int partialAlpha = (int) (alpha * normalized);
super.setAlpha(partialAlpha);
super.draw(canvas);//画bitmap时加上透明度的渐变,时长为200ms
super.setAlpha(alpha);//版本大于10会自动redrawn
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) { // 10
invalidateSelf(); // Use the current Drawable.Callback implementation to have this
// Drawable redrawn. Does nothing if there is no Callback attached to the Drawable.
}      }
}
if (debugging) { // 画左上的三角形
drawDebugIndicator(canvas);
}
}

@Override public void setAlpha(int alpha) {
this.alpha = alpha;
if (placeholder != null) {      placeholder.setAlpha(alpha);    }
super.setAlpha(alpha);
}
@Override public void setColorFilter(ColorFilter cf) {
if (placeholder != null) {      placeholder.setColorFilter(cf);    }
super.setColorFilter(cf);
}
@Override protected void onBoundsChange(Rect bounds) {
if (placeholder != null) {      placeholder.setBounds(bounds);    }
super.onBoundsChange(bounds);
}

private void drawDebugIndicator(Canvas canvas) {// 见上图三角
DEBUG_PAINT.setColor(WHITE);
Path path = getTrianglePath(new Point(0, 0), (int) (16 * density));
canvas.drawPath(path, DEBUG_PAINT);
DEBUG_PAINT.setColor(loadedFrom.debugColor);
path = getTrianglePath(new Point(0, 0), (int) (15 * density));
canvas.drawPath(path, DEBUG_PAINT);
}
private static Path getTrianglePath(Point p1, int width) {
Point p2 = new Point(p1.x + width, p1.y);
Point p3 = new Point(p1.x, p1.y + width);
Path path = new Path();
path.moveTo(p1.x, p1.y);
path.lineTo(p2.x, p2.y);
path.lineTo(p3.x, p3.y);
return path;
}
}


3 Request和RequestCreator相关

1 Transformation 接口

/** Image transformation. */
public interface Transformation {
/**回收
* Transform the source bitmap into a new bitmap. If you create a new bitmap instance, you must
* call {@link Bitmap#recycle()} on {@code source}. You may return the original
* if no transformation is required. !!!
*/
Bitmap transform(Bitmap source);
/**
* Returns a unique key for the transformation, used for caching purposes. If the
* transformation has parameters (e.g. size, scale factor, etc) then these should be part of
* the key. !!!  */
String key();
}


2 Request

一个Request对应一个图片请求

注意构造函数是私有的,需要使用build进行维护,即build是其经纪人

/*Immutable不可改变的 data about an image and the transformations that will be applied to it. */
public final class Request {
private static final long TOO_LONG_LOG = TimeUnit.SECONDS.toNanos(5);//5000000000,10的9次方
int id;  /** A unique ID for the request. */
long started;  /** The time that the request was first submitted (in nanos). */
int networkPolicy;  /** The {@link NetworkPolicy} to use for this request. */
// The image URI.This is mutually exclusive with {@link #resourceId}.互斥的
public final Uri uri;
// The image resource ID. This is mutually exclusive with {@link #uri}.
public final int resourceId;
/**
* Optional stable key for this request to be used instead of the URI or resource ID when
* caching. Two requests with the same value are considered to be for the same resource.
*/
public final String stableKey;
/** List of custom transformations to be applied after the built-in transformations. */
public final List<Transformation> transformations;
/** Target image width for resizing. */
public final int targetWidth;
/** Target image height for resizing. */
public final int targetHeight;
/**
* True if the final image should use the 'centerCrop' scale technique.
* This is mutually exclusive with {@link #centerInside}.
*/
public final boolean centerCrop;
public final boolean centerInside;

public final boolean onlyScaleDown; //只能缩小
/** Amount to rotate the image in degrees. */
public final float rotationDegrees;
/** Rotation pivot中心点 on the X axis. */
public final float rotationPivotX;
/** Rotation pivot on the Y axis. */
public final float rotationPivotY;
/** Whether or not rotationPivotX and rotationPivotY are set. */
public final boolean hasRotationPivot;
/** True if image should be decoded with inPurgeable and inInputShareable.!!! */
public final boolean purgeable; // 可清除的
/** Target image config for decoding. */
public final Bitmap.Config config;
/** The priority of this request. */
public final Priority priority; // 高低NORMAL
// 私有的构造函数,因此必须使用builder
private Request(Uri uri, int resourceId, String stableKey, List<Transformation> transformations,
int targetWidth, int targetHeight, boolean centerCrop, boolean centerInside,
boolean onlyScaleDown, float rotationDegrees, float rotationPivotX, float rotationPivotY,
boolean hasRotationPivot, boolean purgeable, Bitmap.Config config, Priority priority) {
if (transformations == null) {
this.transformations = null;
} else {
this.transformations = unmodifiableList(transformations);
}
}

String logId() {
long delta = System.nanoTime() - started;
if (delta > TOO_LONG_LOG) {
return plainId() + '+' + TimeUnit.NANOSECONDS.toSeconds(delta) + 's';
}
return plainId() + '+' + TimeUnit.NANOSECONDS.toMillis(delta) + "ms";
}
String plainId() {    return "[R" + id + ']';  }

String getName() { //互斥
if (uri != null) {      return String.valueOf(uri.getPath());    }
return Integer.toHexString(resourceId);
}
public boolean hasSize() {    return targetWidth != 0 || targetHeight != 0;  }
boolean needsTransformation() {
return needsMatrixTransform() || hasCustomTransformations();
}
boolean needsMatrixTransform() {    return hasSize() || rotationDegrees != 0;  }
boolean hasCustomTransformations() {    return transformations != null;  }

public Builder buildUpon() {    return new Builder(this); }
/** Builder for creating {@link Request} instances. !!!*/
public static final class Builder {
// 变量又重新定义了一遍
/** Start building a request using the specified {@link Uri}. */
public Builder(Uri uri) { // 构造函数
setUri(uri);
}
/** Start building a request using the specified resource ID. */
public Builder(int resourceId) { // 构造函数
setResourceId(resourceId);
}
Builder(Uri uri, int resourceId, Bitmap.Config bitmapConfig) { // 构造函数
this.uri = uri;
this.resourceId = resourceId;
this.config = bitmapConfig;
}

private Builder(Request request) { // 私有的构造函数
uri = request.uri;
if (request.transformations != null) {
transformations = new ArrayList<Transformation>(request.transformations);
} // ...
}

boolean hasImage() {      return uri != null || resourceId != 0;    }
boolean hasSize() {      return targetWidth != 0 || targetHeight != 0;    }
boolean hasPriority() {      return priority != null;    }

public Builder setUri(Uri uri) {
if (uri == null) {throw new IllegalArgumentException("Image URI may not be null.");      }
this.uri = uri;
this.resourceId = 0;
return this;
}
public Builder setResourceId(int resourceId) {
if (resourceId == 0) {throw new IllegalArgumentException("Image resource ID may 0.");     }
this.resourceId = resourceId;
this.uri = null;
return this;
}

/** Set the stable key to be used instead of the URI or resource ID when caching.
* Two requests with the same value are considered to be for the same resource.    */
public Builder stableKey(String stableKey) {
this.stableKey = stableKey;
return this;
}
/**Clear the resize transformation, if any. This will also clear center crop/inside if set. */
public Builder clearResize() {
targetWidth = 0;      targetHeight = 0;
centerCrop = false;      centerInside = false;
return this;
}

/** Create the immutable {@link Request} object. */
public Request build() {
if (centerInside && centerCrop) {
throw new IllegalStateException("Center crop and center inside can not be used together.");
}//...
if (priority == null) {        priority = Priority.NORMAL;      }
return new Request(uri, resourceId, stableKey, transformations, targetWidth, targetHeight,
centerCrop, centerInside, onlyScaleDown, rotationDegrees, rotationPivotX,
rotationPivotY, hasRotationPivot, purgeable, config, priority);
}
}
}


3 RequestCreator

/** Fluent API for building an image download request.一个方便的API用于创建.. */


一个RequestCreator维护一个Request吧,将Request和Action连接起来!!!!

Callback接口

public interface Callback {
void onSuccess();
void onError();
public static class EmptyCallback implements ICallback {
@Override public void onSuccess() {    }
@Override public void onError() {    }
}
}


public class RequestCreator { // 最终加载进控件的函数在这里可找到如into(view)
private static final AtomicInteger nextId = new AtomicInteger();
private final Picasso picasso; //
private final Request.Builder data; // 用于new Request
private boolean noFade; // PicassoDrawable下会用?
private boolean deferred; // DeferredRequestCreator?
private boolean setPlaceholder = true;
private int placeholderResId;
private int errorResId;
private int memoryPolicy;
private int networkPolicy;
private Drawable placeholderDrawable;
private Drawable errorDrawable;
private Object tag;

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; // 创建builder经纪人,其余参数调用函数可设置
this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);
}
RequestCreator() {//构造函数
this.picasso = null;
this.data = new Request.Builder(null, 0, null);
}

/**Explicitly明确地 opt-out自愿退出; 不参加
* Explicitly opt-out to having a placeholder set when calling {@code into}.调用into函数
* By default, Picasso will either set a supplied placeholder or clear the target
* {@link ImageView} in order to ensure behavior in situations where views are recycled. This
* method will prevent that behavior and retain any already set image保持已经设置好的图像,不用placeholder去设置了.   */
public RequestCreator noPlaceholder() {
if (placeholderResId != 0) {      throw new IllegalStateException("Placeholder resource already set.");    }
if (placeholderDrawable != null) {      throw new IllegalStateException("Placeholder image already set.");    }
setPlaceholder = false;
return this;
}

/** 注释重要!!!
* A placeholder drawable to be used while the image is being loaded. If the requested image is
* not immediately available in the memory cache then this resource will be set on the target
* {@link ImageView}.
* If you are not using a placeholder image but want to clear an existing image (such as when
* used in an {@link android.widget.Adapter adapter}), pass in {@code null}. !!adapte
*/
public RequestCreator placeholder(Drawable placeholderDrawable) {
if (!setPlaceholder) {
throw new IllegalStateException("Already explicitly declared as no placeholder.");
}
if (placeholderResId != 0) {
throw new IllegalStateException("Placeholder image already set.");
}
this.placeholderDrawable = placeholderDrawable;
return this;
}

/** 小心内存泄露
* public RequestCreator tag(Object tag)
Assign a tag to this request. Tags are an easy way to logically associate related requests
that can be managed together e.g. paused, resumed, or canceled.
You can either use simple String tags or objects that naturally define the scope of your
requests within your app such as a android.content.Context, an android.app.Activity, or a
android.app.Fragment. WARNING:: Picasso will keep a reference to the tag for as long as this
tag is paused and/or has active requests. Look out for potential潜在的 leaks. */

/**
* Attempt to resize the image to fit exactly into the target {@link ImageView}'s bounds. This
*will result in delayed execution of the request until the {@link ImageView} has been laid out.
* This method works only when your target is an {@link ImageView}.
* deferred代表了是否拥有fit属性 /
public RequestCreator fit() { //如果fit的话就需要defered推迟
deferred = true;    return this;
}
/** Internal use only. Used by {@link ZDeferredRequestCreator}. */
RequestCreator unfit() {
deferred = false;    return this;
}

// int targetWidth = resources.getDimensionPixelSize(targetWidthResId);
// 一些函数的逻辑,调用RequestCreator的centerCrop()函数等,会调用builder的对应函数,设置经纪人的参数,
// 最终影响到builder创建出来的Request

/** data.onlyScaleDown();
* Only resize an image if the original image size is bigger than the target size
* specified by {@link #resize(int, int)}.
*/

/**
* Attempt to decode the image using the specified config.
* Note: This value may be ignored by BitmapFactory. See its documentation for more details.
*/
public RequestCreator config(Bitmap.Config config) {
data.config(config);    return this;
}

/** 留着是因为暂时无法确定其具体含义
* Sets the stable key for this request to be used instead of the URI or resource ID when
* caching. Two requests with the same value are considered to be for the same resource.
*/
public RequestCreator stableKey(String stableKey) {
data.stableKey(stableKey);    return this;
}

/**
* public RequestCreator priority(Picasso.Priority priority)
Set the priority of this request.
This will affect the order in which the requests execute but does not guarantee it. By
default, all requests have Picasso.Priority.NORMAL priority, except for fetch() requests,
which have Picasso.Priority.LOW priority by default.
*/
/** netPolicy类似
* Specifies the {@link MemoryPolicy} to use for this request. You may specify
*  additional policy options using the varargs变 parameter.
*/
public RequestCreator memoryPolicy(MemoryPolicy policy, MemoryPolicy... additional) {
if (policy == null) {
throw new IllegalArgumentException("Memory policy cannot be null.");
}
this.memoryPolicy |= policy.index;
if (additional == null) {
throw new IllegalArgumentException("Memory policy cannot be null.");
}
if (additional.length > 0) {
for (MemoryPolicy memoryPolicy : additional) {
if (memoryPolicy == null) {
throw new IllegalArgumentException("Memory policy cannot be null.");
}
this.memoryPolicy |= memoryPolicy.index;
}
}
return this;
}

/** Set inPurgeable and inInputShareable when decoding. This will force the bitmap to be decoded from a byte array instead of a stream, since inPurgeable only affects the former.
Note: as of API level 21 (Lollipop), the inPurgeable field is deprecated and will be ignored.
见picasso01,设置Options.inPurgeable和inInputShareable:让系统能及时回收内存。*/
public RequestCreator purgeable() {
data.purgeable();
return this;
}
// ==== GetAction 这里不从缓存中查询,其余的都查询了
/**同步地,因此不要再主线程,---get()和fetch()和into()的区别,
对比:get是同步获取,没有回调,像是重新加载一次图片,因此不要在主线程,因为可能耗时;
fetch是异步获取且有回调,into异步的和控件相关
这几个函数都是针对不同action而存在的,其中会生成request,之后生成action,然后加入到请求队列
* enqueueAndSubmit()--picasso.submit()---hunt()获取图片的具体方式
* Synchronously fulfill this request. Must not be called from the main thread.
* <em>Note</em>: The result of this operation is not cached in memory because the underlying
* {@link Cache} implementation is not guaranteed to be thread-safe.线程安全
*/
public Bitmap get() throws IOException { // 使用的是GetAction
long started = System.nanoTime();
checkNotMain(); //需要在非主线程!!!
if (deferred) {
throw new IllegalStateException("Fit cannot be used with get.");
}
if (!data.hasImage()) {
return null;
}
Request finalData = createRequest(started);
String key = createKey(finalData, new StringBuilder());//包含了各种变换参数
Action action = new GetAction(picasso, finalData, memoryPolicy, networkPolicy, tag, key);
// 调用BitmapHunter去获取图片!!!GetAction只是获取图片,自己不使用,传给调用者
return forRequest(picasso, picasso.dispatcher, picasso.cache, picasso.stats, action).hunt();
}
/** Create the request optionally passing it through the request transformer. */
private Request createRequest(long started) { // 根据当前的builder创建Request并设置id等
int id = nextId.getAndIncrement(); //AtomicInteger
Request request = data.build();
request.id = id;
request.started = started;
boolean loggingEnabled = picasso.loggingEnabled;
if (loggingEnabled) { // created
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) { // changed
log(OWNER_MAIN, VERB_CHANGED, transformed.logId(), "into " + transformed);
}
}
return transformed;
}
// ====FetchAction
/**----without a {@link ImageView} or {@link ITarget}
* Asynchronously异步的 fulfills the request without a {@link ImageView} or {@link ITarget},
* and invokes the target {@link ICallback} with the result. This is useful when you want
* to warm up the cache with an image.
* It is safe to invoke this method from any thread.
* <em>Note:</em> The {@link Callback} param is a strong reference and will prevent your
* {@link android.app.Activity} or {@link android.app.Fragment} from being garbage collected
* until the request is completed. 强引用
*/
public void fetch(Callback callback) { // 使用的是FetchAction
long started = System.nanoTime();
if (deferred) {
throw new IllegalStateException("Fit cannot be used with fetch.");
}
if (data.hasImage()) {
// Fetch requests have lower priority by default.
if (!data.hasPriority()) {
data.priority(Priority.LOW);
}
Request request = createRequest(started);
String key = createKey(request, new StringBuilder());
if (shouldReadFromMemoryCache(memoryPolicy)) {
Bitmap bitmap = picasso.quickMemoryCacheCheck(key);
if (bitmap != null) {
if (picasso.loggingEnabled) { // completed
log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY);
}
if (callback != null) {
callback.onSuccess();
}
return;
}
}
Action action =
new FetchAction(picasso, request, memoryPolicy, networkPolicy, tag, key, callback);
picasso.submit(action);
}
}

/** =====TargetAction
* Asynchronously fulfills the request into the specified {@link ITarget}. In most cases, you
* should use this when you are dealing with a custom {@link android.view.View View} or view
* holder which should implement the {@link Target} interface.
* This method keeps a weak reference to the {@link Target} instance and will be 弱引用
* garbage collected if you do not keep a strong reference to it. To receive callbacks when an
* image is loaded use {@link #into(ImageView, ICallback)}.
*/
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.");
}
if (!data.hasImage()) {
picasso.cancelRequest(target);
target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null);
return;
}
Request request = createRequest(started);
String requestKey = createKey(request);
if (shouldReadFromMemoryCache(memoryPolicy)) {
Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
if (bitmap != null) {
picasso.cancelRequest(target);
target.onBitmapLoaded(bitmap, MEMORY);
return;
}
}
target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null);
Action action = new TargetAction(picasso, target, request, memoryPolicy, networkPolicy,
errorDrawable, requestKey, tag, errorResId);
picasso.enqueueAndSubmit(action);
}

/** =====NotificationAction
* Asynchronously fulfills the request into the specified {@link RemoteViews} object with the
* given {@code viewId}. This is used for loading bitmaps into a {@link Notification}.
*/
public void into(RemoteViews remoteViews, int viewId, int notificationId,
Notification notification, String notificationTag) {
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 = createRequest(started);
String key = createKey(request, new StringBuilder()); // Non-main thread needs own builder.
RemoteViewsAction action =
new NotificationAction(picasso, request, remoteViews, viewId, notificationId,
notification, notificationTag, memoryPolicy, networkPolicy, key, tag, errorResId);
performRemoteViewInto(action);
}

/**  =======AppWidgetAction
* Asynchronously fulfills the request into the specified {@link RemoteViews} object with the
* given {@code viewId}. This is used for loading bitmaps into all instances of a 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 = createRequest(started);
String key = createKey(request, new StringBuilder()); // Non-main thread needs own builder.
RemoteViewsAction action =
new AppWidgetAction(picasso, request, remoteViews, viewId, appWidgetIds, memoryPolicy,
networkPolicy, key, tag, errorResId);
performRemoteViewInto(action);
}
private void performRemoteViewInto(BBRemoteViewsAction action) {
if (shouldReadFromMemoryCache(memoryPolicy)) {
Bitmap bitmap = picasso.quickMemoryCacheCheck(action.getKey());
if (bitmap != null) {
action.complete(bitmap, MEMORY);
return;
}
}
if (placeholderResId != 0) {
action.setImageResource(placeholderResId);
}
picasso.enqueueAndSubmit(action);
}

/** ====ImageViewAction
* Asynchronously fulfills the request into the specified {@link ImageView} and invokes the
* target {@link ICallback} if it's not {@code null}.
* <em>Note:</em> The {@link ICallback} param is a strong reference and will prevent your
* {@link android.app.Activity} or {@link android.app.Fragment} from being garbage collected.
* If you use this method, it is <b>strongly</b> recommended you invoke an adjacent相邻的
* {@link Picasso#cancelRequest(ImageView)} call to prevent temporary leaking.
*/
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) { //说明调用了fit(),此时说明目标view的宽高未定,因此使用DeferredRequestCreator
// 目的是等待宽高定了后在DeferredRequestCreator下的onPreDraw中去再次
// unfit().resize(width, height).into(target, callback);这样就不走这个逻辑了
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) { // 当有一个为0时的处理即view未创建成功
if (setPlaceholder) {
setPlaceholder(target, getPlaceholderDrawable());
}
picasso.defer(target, new DeferredRequestCreator(this, target, callback));// defer的处理
return;
}
data.resize(width, height);//比如复用了一个view
}
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 Drawable getPlaceholderDrawable() {
if (placeholderResId != 0) {
return picasso.context.getResources().getDrawable(placeholderResId);
} else {
return placeholderDrawable; // This may be null which is expected and desired behavior.
}
}
}


4 DeferredRequestCreator

defer推迟, 将RequestCreator进行了封装,

into(ImageView target, Callback callback) 中当有一个为0时的处理,会用这个类,或许另一层含义是

target没创建好,所以width或height的值会为0,因此需要defered

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);//add
}
@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); // remove
// unfit-->deferred = false;
this.creator.unfit().resize(width, height).into(target, callback);
return true;
}

void cancel() {
creator.clearTag();
callback = null;
ImageView target = this.target.get();
if (target == null) {      return;    }
ViewTreeObserver vto = target.getViewTreeObserver();
if (!vto.isAlive()) {      return;    }
vto.removeOnPreDrawListener(this);
}
Object getTag() {    return creator.getTag();  }
}


4 MarkableInputStream

unlimited无限的 independent自主的 cursors注意复数啊!!

这个类倒着看好点理解,

1 注意:mark就像书签一样,在这个BufferedReader对应的buffer里作个标记,以后再调用reset时就可以再回到这个mark过的地方。mark方法有个参数,通过这个整型参数,你告诉系统,希望在读出这么多个字符之前,这个mark保持有效。读过这么多字符之后,系统可以使mark不再有效,而你不能觉得奇怪或怪罪它。这跟buffer有关,如果你需要很长的距离,那么系统就必须分配很大的buffer来保持你的mark。

reader.mark(50);//要求在50个字符之内,这个mark应该保持有效,系统会保证buffer至少可以存储50个字符

2. 对于BufferedInputStream,readlimit表示:InputStream调用mark方法的时刻起,在读取readlimit个字节之前,标记的该位置是有效的。如果读取的字节数大于readlimit,可能标记的位置会失效。
在BufferedInputStream的read方法源码中有这么一段:
} else if (buffer.length >= marklimit) {
markpos = -1;   /* buffer got too big, invalidate mark */
pos = 0;        /* drop buffer contents */
} else {            /* grow buffer */
为什么是可能会失效呢?
因为BufferedInputStream读取不是一个字节一个字节读取的,是一个字节数组一个字节数组读取的。
例如,readlimit=35,第一次比较的时候buffer.length=0(没开始读)<readlimit
然后buffer数组一次读取48个字节。这时的read方法只会简单的挨个返回buffer数组中的字节,不会做这次比较。直到读到buffer数组最后一个字节(第48个)后,才重新再次比较。这时如果我们读到buffer中第47个字节就reset。mark仍然是有效的。虽然47>35。 http://zhangbo-peipei-163-com.iteye.com/blog/2022460[/code] 
/**
* An input stream wrapper that supports unlimited independent cursors for
* marking and resetting. Each cursor is a token, and it's the caller's
* responsibility to keep track of these.
*/
final class MarkableInputStream extends InputStream {
private static final int DEFAULT_BUFFER_SIZE = 4096;
private final InputStream in;

private long offset;
private long reset;
private long limit;
private long defaultMark = -1;

public MarkableInputStream(InputStream in) {
this(in, DEFAULT_BUFFER_SIZE);
}
public MarkableInputStream(InputStream in, int size) {
// Indicates whether this stream supports the mark() and reset() methods.
if (!in.markSupported()) {
in = new BufferedInputStream(in, size);//不支持就利用BufferedInputStream使其支持
}
this.in = in;
}

/** Marks this place in the stream so we can reset back to it later. */
@Override public void mark(int readLimit) {
defaultMark = savePosition(readLimit);
}

/**
* Returns an opaque不透明的 token记号 representing the current position in the stream.
* Call {@link #reset(long)} to return to this position in the stream later.
* It is an error to call {@link #reset(long)} after consuming more than
* {@code readLimit} bytes from this stream.
*/
public long savePosition(int readLimit) {
long offsetLimit = offset + readLimit;
if (limit < offsetLimit) {
setLimit(offsetLimit);
}
return offset;
}

/**
* Makes sure that the underlying stream can backtrack the full range from
* {@code reset} thru {@code limit}. Since we can't call {@code mark()}
* without also adjusting the reset-to-position on the underlying stream this
* method resets first and then marks the union of the two byte ranges. On
* buffered streams this additional cursor motion shouldn't result in any
* additional I/O.
*/
private void setLimit(long limit) {
try {
if (reset < offset && offset <= this.limit) {
in.reset();
in.mark((int) (limit - reset));
skip(reset, offset);
} else {
reset = offset;
in.mark((int) (limit - offset));
}
this.limit = limit;
} catch (IOException e) {
throw new IllegalStateException("Unable to mark: " + e);
}
}

/** Resets the stream to the most recent {@link #mark mark}. */
@Override public void reset() throws IOException {
reset(defaultMark);
}

/** Resets the stream to the position recorded by {@code token}. */
public void reset(long token) throws IOException {
if (offset > limit || token < reset) {
throw new IOException("Cannot reset");
}
in.reset();
skip(reset, token); // skip的个数
offset = token; // 保存个数为offset
}

/** Skips (target - current) bytes and returns. */
private void skip(long current, long target) throws IOException {
while (current < target) {
long skipped = in.skip(target - current);
if (skipped == 0) {
if (read() == -1) {
break; // EOF
} else {
skipped = 1;
}
}
current += skipped;
}
}

@Override public int read() throws IOException {
int result = in.read();
if (result != -1) {
offset++;
}
return result;
}

@Override public int read(byte[] buffer) throws IOException {
int count = in.read(buffer);
if (count != -1) {
offset += count;
}
return count;
}

@Override public int read(byte[] buffer, int offset, int length) throws IOException {
int count = in.read(buffer, offset, length);
if (count != -1) {
this.offset += count;
}
return count;
}

@Override public long skip(long byteCount) throws IOException {
long skipped = in.skip(byteCount);
offset += skipped;
return skipped;
}

@Override public int available() throws IOException {
return in.available();
}

@Override public void close() throws IOException {
in.close();
}

@Override public boolean markSupported() {
return in.markSupported();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  picasso