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);
}
發佈了20 篇原創文章 · 獲贊 5 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章