Picasso分析01

1 RequestHandler

1 RequestHandler抽象类

根据图片来源的不同,构建不同的请求对象,如图片来自网络、文件、assert、多媒体等;
在Picasso库中已经实现了常用的请求,但我们可以根据新需求进行扩展,记得注册自己写的;
即 register your RequestHandler using Picasso.Builder.addRequestHandler(RequestHandler)

 public static final class Result { // RequestHandler的内部类,返回的结果数据
    // MEMORY(Color.GREEN),DISK(Color.BLUE),NETWORK(Color.RED)
    private final Picasso.LoadedFrom loadedFrom;     
    private final Bitmap bitmap;
    private final InputStream stream;
    private final int exifOrientation;
    Result(Bitmap bitmap, InputStream stream, Picasso.LoadedFrom loadedFrom, int exifOrientation)
    {    // mutually exclusive event 互斥事件
      if (!(bitmap != null ^ stream != null)) { // 异或,即两者只能有一个不为null,两者是互斥关系
        throw new AssertionError();
      }
      this.bitmap = bitmap;
      this.stream = stream;
      this.loadedFrom = checkNotNull(loadedFrom, "loadedFrom == null");
      this.exifOrientation = exifOrientation;
    }
  }

【备注:exifOrientation信息来自http://blog.csdn.net/ouyangtianhan/article/details/29825885
http://www.impulseadventure.com/photo/exif-orientation.html
EXIF Orientation 参数让你随便照像但都可以看到正确方向的照片而无需手动旋转;
下图0行代表第0行在图片的方位

备注结束 】
抽象方法:

   public abstract boolean canHandleRequest(Request data); // 是否可以处理这个请求
   public abstract Result load(Request request, int networkPolicy) throws IOException;//处理  

Retry相关

  int getRetryCount() {    return 0;  }
  boolean shouldRetry(boolean airplaneMode, NetworkInfo info) {    return false;  }
  boolean supportsReplay() {    return false;  }

Bitmap的配置工具

  static BitmapFactory.Options createBitmapOptions(Request data) {
    final boolean justBounds = data.hasSize();//目标控件是否有大小尺寸
    final boolean hasConfig = data.config != null;
    BitmapFactory.Options options = null;
// 设置Options.inPurgeable和inInputShareable:让系统能及时回收内存。
// 1)inPurgeable:设置为True时,表示系统内存不足时可以被回 收,设置为False时,表示不能被回收。
// 2)inInputShareable:设置是否深拷贝,与inPurgeable结合使用,inPurgeable为false时,该参数无意义
//   True:  share  a reference to the input data(inputStream, array,etc) 。 False :a deep copy。
    if (justBounds || hasConfig || data.purgeable) {// purgeable可清除的
      options = new BitmapFactory.Options();
      options.inJustDecodeBounds = justBounds;
      options.inInputShareable = data.purgeable;
      options.inPurgeable = data.purgeable;
      if (hasConfig) {
        options.inPreferredConfig = data.config;
      }
    }
    return options;
  }
  static void calculateInSampleSize(int reqWidth, int reqHeight, int width, int height,
      BitmapFactory.Options options, Request request) {
    int sampleSize = 1;
    if (height > reqHeight || width > reqWidth) {
      final int heightRatio;
      final int widthRatio;
      if (reqHeight == 0) {
        sampleSize = (int) Math.floor((float) width / (float) reqWidth);
      } else if (reqWidth == 0) {
        sampleSize = (int) Math.floor((float) height / (float) reqHeight);
      } else {
        heightRatio = (int) Math.floor((float) height / (float) reqHeight);
        widthRatio = (int) Math.floor((float) width / (float) reqWidth);
        sampleSize = request.centerInside ? Math.max(heightRatio, widthRatio)
            : Math.min(heightRatio, widthRatio);//max则需要全部显示的
      }
    }
    options.inSampleSize = sampleSize;
    options.inJustDecodeBounds = false;//大小已经计算好了,可以加载了baby
  }

接着按照Picasso初始化时RequestHandler的添加顺序依次介绍子类

2 子类之ResourceRequestHandler

图片来自资源文件

    // 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.
class ResourceRequestHandler extends RequestHandler {
  @Override public boolean canHandleRequest(Request data) {
    if (data.resourceId != 0) {
      return true;
    } // SCHEME_ANDROID_RESOURCE = "android.resource";
    return SCHEME_ANDROID_RESOURCE.equals(data.uri.getScheme());
  }
  @Override public Result load(Request request, int networkPolicy) throws IOException {
    Resources res = Utils.getResources(context, request);//context.getResources();
    int id = Utils.getResourceId(res, request);//data.resourceId;
    return new Result(decodeResource(res, id, request), DISK);//返回的是Bitmap哦,不是流
  }
  private static Bitmap decodeResource(Resources resources, int id, Request data) {
    final BitmapFactory.Options options = createBitmapOptions(data);
    if (requiresInSampleSize(options)) {//是否需要计算要加载的大小
      BitmapFactory.decodeResource(resources, id, options);//获得图片的尺寸
      calculateInSampleSize(data.targetWidth, data.targetHeight, options, data);//裁剪
    }
    return BitmapFactory.decodeResource(resources, id, options);
  }
}

3 子类之ContactsPhotoRequestHandler

图片来自ContactsPhoto

class ContactsPhotoRequestHandler extends RequestHandler {
  /** A lookup uri (e.g. content://com.android.contacts/contacts/lookup/3570i61d948d30808e537) */
  private static final int ID_LOOKUP = 1;
  /** A contact thumbnail uri (e.g. content://com.android.contacts/contacts/38/photo) */
  private static final int ID_THUMBNAIL = 2; //  thumbnail是缩略图
  /** A contact uri (e.g. content://com.android.contacts/contacts/38) */
  private static final int ID_CONTACT = 3;
  /**
   * A contact display photo (high resolution分辨率) uri
   * (e.g. content://com.android.contacts/display_photo/5)
   */
  private static final int ID_DISPLAY_PHOTO = 4;

  private static final UriMatcher matcher;
  static {
    matcher = new UriMatcher(UriMatcher.NO_MATCH);
    matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", ID_LOOKUP);
    matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", ID_LOOKUP);
    matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", ID_THUMBNAIL);
    matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", ID_CONTACT);
    matcher.addURI(ContactsContract.AUTHORITY, "display_photo/#", ID_DISPLAY_PHOTO);
  }
  @Override public boolean canHandleRequest(Request data) {
    final Uri uri = data.uri; // SCHEME_CONTENT = "content"
    // CONTENT_URI.getHost()的值为com.android.contacts
    return (SCHEME_CONTENT.equals(uri.getScheme())
        && ContactsContract.Contacts.CONTENT_URI.getHost().equals(uri.getHost())
        && matcher.match(data.uri) != UriMatcher.NO_MATCH);
  }
  @Override public Result load(Request request, int networkPolicy) throws IOException {
    InputStream is = getInputStream(request);
    return is != null ? new Result(is, DISK) : null; //返回的是流
  }

  private InputStream getInputStream(Request data) throws IOException {
    ContentResolver contentResolver = context.getContentResolver();
    Uri uri = data.uri;
    switch (matcher.match(uri)) {
      case ID_LOOKUP:
        uri = ContactsContract.Contacts.lookupContact(contentResolver, uri);
        if (uri == null) {
          return null;
        }
    // Resolved the uri to a contact uri, intentionally fall through to process the resolved uri
      case ID_CONTACT:
        if (SDK_INT < ICE_CREAM_SANDWICH) {
          return openContactPhotoInputStream(contentResolver, uri);
        } else {
          return ContactPhotoStreamIcs.get(contentResolver, uri);
        }
      case ID_THUMBNAIL:
      case ID_DISPLAY_PHOTO:
        return contentResolver.openInputStream(uri);
      default:
        throw new IllegalStateException("Invalid uri: " + uri);
    }
  }

  @TargetApi(ICE_CREAM_SANDWICH)
  private static class ContactPhotoStreamIcs {
    static InputStream get(ContentResolver contentResolver, Uri uri) {
      return openContactPhotoInputStream(contentResolver, uri, true);
    }
  }
}

4 子类之MediaStoreRequestHandler

先看第5个,然后看这个吧
【Uri参考http://blog.csdn.net/harvic880925/article/details/44679239
基本形式[scheme:]scheme-specific-part[#fragment]
进一步划分[scheme:][//authority][path][?query][#fragment]
path可以有多个,每个用/连接,scheme://authority/path1/path2/path3?query#fragment
query参数可以带有对应的值,也可以不带,如果带对应的值用=表示,如
scheme://authority/path1/path2/path3?id = 1#fragment,这里有一个参数id,它的值是1
query参数可以有多个,每个用&连接
scheme://authority/path1/path2/path3?id = 1&name = mingming&old#fragment
这里有三个参数:
参数1:id,其值是:1,参数2:name,其值是:mingming,参数3:old,没有对它赋值,所以它的值是null
在android中,除了scheme、authority是必须要有的,其它的几个path、query、fragment,它们每一个可以选择性的要或不要,但顺序不能变,比如:

其中"path"可不要:scheme://authority?query#fragment
其中"path""query"可都不要:scheme://authority#fragment
其中"query""fragment"可都不要:scheme://authority/path
"path","query","fragment"都不要:scheme://authority等等

其中authority,又可以分为host:port的形式,即再次划分后是这样的:
[scheme:][//host:port][path][?query][#fragment]
所以这是划分最细的形式,其中host:port用冒号分隔,冒号前的是host,冒号后的port;

class MediaStoreRequestHandler extends ContentStreamRequestHandler {
  private static final String[] CONTENT_ORIENTATION = new String[] {
      Images.ImageColumns.ORIENTATION // ORIENTATION = "orientation"
  };
  @Override public boolean canHandleRequest(Request data) {
    final Uri uri = data.uri;
    return (SCHEME_CONTENT.equals(uri.getScheme())
            && MediaStore.AUTHORITY.equals(uri.getAuthority()));
  }

  @Override public Result load(Request request, int networkPolicy) throws IOException {
    ContentResolver contentResolver = context.getContentResolver();
    int exifOrientation = getExifOrientation(contentResolver, request.uri);
    // getType的返回结果是需要自己去定义的,即这里系统根据Uri定义好了返回值。另可以设置intent.setType(type)。
    String mimeType = contentResolver.getType(request.uri);
    boolean isVideo = mimeType != null && mimeType.startsWith("video/");
    if (request.hasSize()) {
      PicassoKind picassoKind = getPicassoKind(request.targetWidth, request.targetHeight);
      if (!isVideo && picassoKind == FULL) {
        return new Result(null, getInputStream(request), DISK, exifOrientation);
      }
      long id = parseId(request.uri);
      BitmapFactory.Options options = createBitmapOptions(request);
      options.inJustDecodeBounds = true;
      calculateInSampleSize(request.targetWidth, request.targetHeight, picassoKind.width,
              picassoKind.height, options, request);
      Bitmap bitmap;
      if (isVideo) {
        // Since MediaStore doesn't provide the full screen kind thumbnail, we use the mini kind
        // instead which is the largest thumbnail size can be fetched from MediaStore.
        int kind = (picassoKind == FULL) ? Video.Thumbnails.MINI_KIND : picassoKind.androidKind;
        bitmap = Video.Thumbnails.getThumbnail(contentResolver, id, kind, options);
      } else {
        bitmap =
            Images.Thumbnails.getThumbnail(contentResolver, id, picassoKind.androidKind, options);
      }
      if (bitmap != null) {
        return new Result(bitmap, null, DISK, exifOrientation);
      }
    }
    return new Result(null, getInputStream(request), DISK, exifOrientation);
  }

  static PicassoKind getPicassoKind(int targetWidth, int targetHeight) {
    if (targetWidth <= MICRO.width && targetHeight <= MICRO.height) {
      return MICRO;
    } else if (targetWidth <= MINI.width && targetHeight <= MINI.height) {
      return MINI;
    }
    return FULL;
  }

  static int getExifOrientation(ContentResolver contentResolver, Uri uri) {
    Cursor cursor = null;
    try {
      cursor = contentResolver.query(uri, CONTENT_ORIENTATION, null, null, null);
      if (cursor == null || !cursor.moveToFirst()) {
        return 0;
      }
      return cursor.getInt(0);
    } catch (RuntimeException ignored) {
      // If the orientation column doesn't exist, assume no rotation.作用是旋转啊
      return 0;
    } finally {
      if (cursor != null) {
        cursor.close();
      }
    }
  }
  enum PicassoKind {
    MICRO(MICRO_KIND, 96, 96),//调用PicassoKind的构造函数并传入了三个参数
    MINI(MINI_KIND, 512, 384),
    FULL(FULL_SCREEN_KIND, -1, -1);
    final int androidKind;
    final int width;
    final int height;
    PicassoKind(int androidKind, int width, int height) {
      this.androidKind = androidKind;
      this.width = width;
      this.height = height;
    }
  }
}

5 子类之ContentStreamRequestHandler

  @Override public boolean canHandleRequest(Request data) {
    return SCHEME_CONTENT.equals(data.uri.getScheme());
  }
  @Override public Result load(Request request, int networkPolicy) throws IOException {
    return new Result(getInputStream(request), DISK);
  }
  InputStream getInputStream(Request request) throws FileNotFoundException {
    ContentResolver contentResolver = context.getContentResolver();
    return contentResolver.openInputStream(request.uri);
  }

6 子类之AssetRequestHandler

首先getPathSegments()测试

Uri.parse("http://com.aa/bb/cc").getPathSegments()的返回结果:  包括bb和cc
Uri.parse("http:///com.aa/bb/cc").getPathSegments()的返回结果: 包括com.aa和bb和cc

因此file:///的结果是authority的值存在但是空白一个,因此多了一个/斜杠

class AssetRequestHandler extends RequestHandler {
  protected static final String ANDROID_ASSET = "android_asset";
  private static final int ASSET_PREFIX_LENGTH = 
      (SCHEME_FILE + ":///" + ANDROID_ASSET + "/").length();
    // 注 SCHEME_FILE = "file";
  private final AssetManager assetManager;
  public AAAssetRequestHandler(Context context) { assetManager = context.getAssets();  }
  @Override public boolean canHandleRequest(Request data) {
    // uri---> content://com.contentprovider.testprovider/lianxiren/100
    // uri.getPathSegments().get(0)---lianxiren
    // uri.getPathSegments().get(1)---100
    Uri uri = data.uri;
    return (SCHEME_FILE.equals(uri.getScheme())        
        && !uri.getPathSegments().isEmpty() && 
        ANDROID_ASSET.equals(uri.getPathSegments().get(0)));
  }
  @Override public Result load(Request request, int networkPolicy) throws IOException {
    InputStream is = assetManager.open(getFilePath(request));//此处返回的是流,不是bitmap,互斥
    return new Result(is, DISK);//返回的结果是Result类
  }
  static String getFilePath(Request request) { //获取文件名称
    return request.uri.toString().substring(ASSET_PREFIX_LENGTH);
  }
}

7 子类之FileRequestHandler

图片来自文件数据

class AAFileRequestHandler extends AAContentStreamRequestHandler {
  @Override public boolean canHandleRequest(Request data) {
    return SCHEME_FILE.equals(data.uri.getScheme());
  }
  @Override public Result load(Request request, int networkPolicy) throws IOException {
    return new Result(null, getInputStream(request), DISK, getFileExifRotation(request.uri));
  }
  static int getFileExifRotation(Uri uri) throws IOException {
    ExifInterface exifInterface = new ExifInterface(uri.getPath());
    return exifInterface.getAttributeInt(TAG_ORIENTATION, ORIENTATION_NORMAL);
  }
}

8 子类之NetworkRequestHandler

图片来源于网络

class NetworkRequestHandler extends RequestHandler {
  static final int RETRY_COUNT = 2;
  private static final String SCHEME_HTTP = "http";
  private static final String SCHEME_HTTPS = "https";
  private final Downloader downloader;
  private final Stats stats;
  @Override public boolean canHandleRequest(Request data) {
    String scheme = data.uri.getScheme();
    return (SCHEME_HTTP.equals(scheme) || SCHEME_HTTPS.equals(scheme));
  }
@Override public Result load(Request request, int networkPolicy) throws IOException {
    Response response = downloader.load(request.uri, request.networkPolicy);
    if (response == null) {      return null;    }
    Picasso.LoadedFrom loadedFrom = response.cached ? DISK : NETWORK;// 缓存意味着本地
    Bitmap bitmap = response.getBitmap();
    if (bitmap != null) {
      return new Result(bitmap, loadedFrom);
    }
    InputStream is = response.getInputStream();
    if (is == null) {
      return null;
    }
    // Sometimes response content length is zero when requests are being replayed. Haven't found
    // root cause to this but retrying the request seems safe to do so.
    if (loadedFrom == DISK && response.getContentLength() == 0) {
      Utils.closeQuietly(is);
      throw new ContentLengthException("Received response with 0 content-length header.");
    }
    if (loadedFrom == NETWORK && response.getContentLength() > 0) {
      stats.dispatchDownloadFinished(response.getContentLength());//更新状态
    }
    return new Result(is, loadedFrom);
  }
  @Override int getRetryCount() {    return RETRY_COUNT;  } //重试机制只有网络会使用到
  @Override boolean shouldRetry(boolean airplaneMode, NetworkInfo info) {
    return info == null || info.isConnected();  
  }
  @Override boolean supportsReplay() {    return true;  }
  @SuppressWarnings("serial")
static class ContentLengthException extends IOException {
    public ContentLengthException(String message) {      super(message);    }
  }
}

2 Action

1 Action抽象类

不同的控件都有显示图片的需求,因此根据这些控件进行分类,添加被回调接口。
如获取到结果后调用此类的回调,如获取成功后将Imageview设置对应的Drawable。
Action行动,活动; 功能,作用; 活动结束后会被执行完成的回调或者错误的回调。

abstract class Action<T> {
  // 内部类,注意泛型T和M的使用,T就是要使用图片的控件!!
  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;
    }
  }
  final Picasso picasso; // final类型都
  final Request request;
  final WeakReference<T> target;// ...其它变量略

  boolean willReplay;
  boolean cancelled;
  BBAction(Picasso picasso, T target, Request request, int memoryPolicy, int networkPolicy,
      int errorResId, Drawable errorDrawable, String key, Object tag, boolean noFade) {
    this.picasso = picasso;
    this.request = request;
    this.target = target == null ? null : 
         new RequestWeakReference<T>(this, target, picasso.referenceQueue);
    this.memoryPolicy = memoryPolicy;
    this.networkPolicy = networkPolicy;
    this.noFade = noFade;
    this.errorResId = errorResId;
    this.errorDrawable = errorDrawable;
    this.key = key;
    this.tag = (tag != null ? tag : this);
  }
  // 抽象方法
  abstract void complete(Bitmap result, Picasso.LoadedFrom from);
  abstract void error();

  void cancel() {    cancelled = true;  }
  T getTarget() {    return target == null ? null : target.get();  }
}

2 FetchAction

注意泛型是Object,只进行了图片的获取工作,之后只是回调了callback函数,泛型Object没有使用到图片。
由于使用了自定义的target,因此需要重写getTarget方法

class FetchAction extends Action<Object> {
  private final Object target; // 注意名字,父类中也有这个名字 final WeakReference<T> target;
  private ICallback callback;
  BBFetchAction(Picasso picasso, Request data, int memoryPolicy, int networkPolicy, Object tag,
      String key, ICallback callback) {
    // 调父类构造第二个参数为null,因此WeakReference<T> target为null,errorResId和errorDrawable都没有
    super(picasso, null, data, memoryPolicy, networkPolicy, 0, null, key, tag, false);
    this.target = new Object();// 新建一个,target和泛型一致
    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 = null; // 及时释放内存
  }
  @Override Object getTarget() {    return target;  } // 覆盖了target的获取,返回自己的target
}

3 GetAction

do nothing,泛型是Void,更使用不到图片了
class BBGetAction extends BBAction<Void>
super(picasso, null, data, memoryPolicy, networkPolicy, 0, null, key, tag, false);

4 ImageViewAction

泛型是ImageView,即ImageView要使用图片

class ImageViewAction extends Action<ImageView> {
  ICallback callback;
  BBImageViewAction(Picasso picasso, ImageView imageView, Request data, int memoryPolicy,
      int networkPolicy, int errorResId, Drawable errorDrawable, String key, Object tag,
      ICallback callback, boolean noFade) { // target即是imageView,使用父类的target
    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;    }
    Drawable placeholder = target.getDrawable();
    if (placeholder instanceof AnimationDrawable) {
      ((AnimationDrawable) placeholder).stop();//stop先
    }
    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;    }
  }
}

5 RemoteViewsAction

泛型是自定义的RemoteViewsTarget,即RemoteViewsTarget会使用到图片,具体是RemoteViewsTarget下的remoteViews
使用自己定义的target,父类的为null,图片获取成功后,
放入RemoteViewsTarget的remoteViews下,供子类去具体使用。注意抽象类,实现为两个内部类。
由于使用了自定义的target,因此需要重写getTarget方法。

abstract class RemoteViewsAction extends Action<RemoteViewsAction.RemoteViewsTarget> {
  final RemoteViews remoteViews;
  final int viewId;
  private RemoteViewsTarget target;
  BBRemoteViewsAction(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;//会存入RemoteViewsTarget中
    this.viewId = viewId;
  }

  @Override void complete(Bitmap result, Picasso.LoadedFrom from) {
    remoteViews.setImageViewBitmap(viewId, result);//设置图片于remoteViews中,子类需要时从此获取
    update();
  }

  @Override public void error() {
    if (errorResId != 0) {
      setImageResource(errorResId);
    }
  }

  @Override RemoteViewsTarget getTarget() {
    if (target == null) {
      target = new RemoteViewsTarget(remoteViews, viewId);// 存入RemoteViewsTarget中
    }
    return target;
  }

  void setImageResource(int resId) {
    remoteViews.setImageViewResource(viewId, resId);
    update();
  }

  abstract void update();//抽象类的抽象方法,内部类会实现

  static class RemoteViewsTarget {//自定义的target类
    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;
    }
  }
  // 第一个实现类,AppWidget类型
  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);
      //appWidgetIds: The AppWidget instances for which to set the RemoteViews.
      manager.updateAppWidget(appWidgetIds, remoteViews);//使用图片的具体控件
    }
  }
 // 第二个实现类,Notification类型
  static class NotificationAction extends BBRemoteViewsAction {
    private final int notificationId;
    private final String notificationTag;
    private final Notification notification;

    NotificationAction(Picasso picasso, Request data, RemoteViews remoteViews, int viewId,
        int notificationId, Notification notification, String notificationTag, int memoryPolicy,
        int networkPolicy, String key, Object tag, int errorResId) {
        // 创建时传入的remoteViews应该已经和通知关联好了
    super(picasso, data, remoteViews, viewId, errorResId, memoryPolicy, networkPolicy, tag, key);
      this.notificationId = notificationId;
      this.notificationTag = notificationTag;
      this.notification = notification;
    }
    @Override void update() {//?没有使用remoteViews啊,没有使用图片??
      NotificationManager manager = getService(picasso.context, NOTIFICATION_SERVICE);
      // 更新通知时会一同更新remoteViews吧,因此使用了...
      manager.notify(notificationTag, notificationId, notification);
    }
  }
}

6 TargetAction

泛型是Target接口,即Target接口会使用到图片,具体就是调用接口时将图片参数传递出去供其他使用。
使用父类的target变量,因此getTarget也是父类的

final class TargetAction extends Action<Target> {
  BBTargetAction(Picasso picasso, ITarget 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));
    }
    ITarget target = getTarget(); // 调用父类的
        if (target != null) {//如还没有被回收
          target.onBitmapLoaded(result, from);// 将图片数据传递给用户
        if (result.isRecycled()) {
            throw new IllegalStateException("Target callback must not recycle bitmap!");
      }
    }
  }
  @Override void error() {
    ITarget target = getTarget();
    if (target != null) {
      if (errorResId != 0) {
        target.onBitmapFailed(picasso.context.getResources().getDrawable(errorResId));
      } else {
        target.onBitmapFailed(errorDrawable);
      }
    }
  }
}

Target接口

/**
 * Represents an arbitrary专制的任性的 listener for image loading.
 * Objects implementing this class <strong>must</strong> have a working implementation of
 * Object.equals(Object) and Object.hashCode() for proper storage internally本地存储.
 * Instances of this interface will also be compared to determine if view recycling is occurring.
 * It is recommended that you add this interface directly on to a custom view type when using in 
 * an adapter to ensure correct recycling behavior.
 */
public interface ITarget {
  // Callback when an image has been successfully loaded. You must not recycle the bitmap.
  void onBitmapLoaded(Bitmap bitmap, LoadedFrom from);

  //Callback indicating the image could not be successfully loaded.
  void onBitmapFailed(Drawable errorDrawable);

  //Callback invoked right before your request is submitted.
  //The passed Drawable may be null if none has been specified via 图片加载成功前应该显示什么缓冲图片
   // RequestCreator.placeholder(Drawable) or RequestCreator.placeholder(int).
  void onPrepareLoad(Drawable placeHolderDrawable);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值