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