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