首先從調用第一行代碼看起
// Trigger the download of the URL asynchronously into the image view.
Picasso.with()
.load(url)
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.resizeDimen(R.dimen.list_detail_image_size,R.dimen.list_detail_image_size)
.centerInside()
.tag(context)
.into(holder.image);
很顯然是單例模式
public staticPicassowith() {
if(singleton==null) {
synchronized(Picasso.class) {
if(singleton==null) {
if(PicassoProvider.context==null) {
throw newIllegalStateException("context == null");
}
singleton=newBuilder(PicassoProvider.context).build();
}
}
}
returnsingleton;
}
裏面還有個PicassoProvider,在這個類裏面直接獲取的Context
@RestrictTo(LIBRARY)
public final class PicassoProvider extends ContentProvider {
static Context context;
@Override public booleanonCreate() {
context= getContext();
return true;
}
再看通過內部Builder的build方法創建一些默認的內部依賴的類.
/** Create the {@linkPicasso} instance. */
public Picasso build() {
Context context =this.context;
if(downloader==null) {
downloader=new OkHttp3Downloader(context);//下載器
}
if(cache==null) {
cache=new LruCache(context);//緩存
}
if(service==null) {
service=new PicassoExecutorService();//線程池
}
if(transformer==null) {
transformer= RequestTransformer.IDENTITY;//Request轉換
}
Stats stats =new Stats(cache);//狀態
Dispatcher dispatcher =new Dispatcher(context,service,HANDLER,downloader,cache,stats);
return new Picasso(context,dispatcher,cache,listener,transformer,requestHandlers,stats,
defaultBitmapConfig,indicatorsEnabled,loggingEnabled);
}
再看
public RequestCreator load(@NullableString path) {
if(path ==null) {
return new RequestCreator(this, null,0);
}
if(path.trim().length() ==0) {
throw new IllegalArgumentException("Path must not be empty.");
}
return load(Uri.parse(path));
}
將String轉換爲Uri,最終調用。生成一個RequestCreator對象。
public RequestCreator load(@NullableUri uri) {
return new RequestCreator(this,uri,0);
}
這個對象存儲了請求的基本信息,如果是請求網絡則第三個參數爲0如果是資源文件則第三個參數就是資源id
public class RequestCreator {
private static final AtomicInteger nextId=newAtomicInteger();
private final Picasso picasso;
private final Request.Builder data;
private boolean noFade;
private boolean deferred;
private boolean setPlaceholder=true;
private int placeholderResId;
private int errorResId;
private int memoryPolicy;
private int networkPolicy;
private Drawable placeholderDrawable;
private Drawable errorDrawable;
private Object tag;
RequestCreator(Picasso picasso,Uri uri, int resourceId) {
if(picasso.shutdown) {
throw new IllegalStateException(
"Picasso instance already shut down. Cannot submit new requests.");
}
this.picasso= picasso;
this.data=new Request.Builder(uri,resourceId,picasso.defaultBitmapConfig);
}
再往下看。設置還未下載圖片之前佔位資源id。
public RequestCreator placeholder(@DrawableRes int placeholderResId) {
if(!setPlaceholder) {//默認這個值爲true,如果調用noPlaceholder方法則爲false
throw new IllegalStateException("Already explicitly declared as no placeholder.");
}
if(placeholderResId ==0) {
throw new IllegalArgumentException("Placeholder image resource invalid.");
}
if(placeholderDrawable!=null) {
throw new IllegalStateException("Placeholder image already set.");
}
this.placeholderResId= placeholderResId;
return this;
}
同樣的設置錯誤是顯示資源Id
/** An error drawable to be used if the request image could not be loaded. */
public RequestCreator error(@DrawableRes int errorResId) {
if(errorResId ==0) {
throw new IllegalArgumentException("Error image resource invalid.");
}
if(errorDrawable!=null) {
throw new IllegalStateException("Error image already set.");
}
this.errorResId= errorResId;
return this;
}
fitz表示要處理下載後的圖片要適應圖片控件的大小
/*** Attempt to resize the image to fit exactly into the target {@linkImageView}'s bounds. This* will result in delayed execution of the request until the {@linkImageView} has been laid out.*
*Note:This method works only when your target is an {@linkImageView}.*/
public RequestCreator fit() {
deferred=true;
return this;
}
Tag表示一個類關聯當前請求,下面有個警告,說只要tag狀態是暫停或者有活動的請求,picasso一直會保持tag的引用,有可能有內存泄露
/*** Assign a tag to this request. Tags are an easy way to logically associate* related requests that can be managed together e.g. paused, resumed,* or canceled.*
* You can either use simple {@linkString} tags or objects that naturally* define the scope of your requests within your app such as a* {@linkandroid.content.Context}, an {@linkandroid.app.Activity}, or a* {@linkandroid.app.Fragment}.**WARNING:: Picasso will keep a reference to the tag for* as long as this tag is paused and/or has active requests. Look out for* potential leaks.**@seePicasso#cancelTag(Object)*@seePicasso#pauseTag(Object)*@seePicasso#resumeTag(Object)*/publicRequestCreatortag(@NonNullObject tag) {
if(tag ==null) {
throw new IllegalArgumentException("Tag invalid.");
}
if(this.tag!=null) {
throw new IllegalStateException("Tag already set.");
}
this.tag= tag;
return this;
}
然後查看into方法,註釋裏面說對target保持弱引用
/*** Asynchronously fulfills the request into the specified {@linkImageView}.*
*Note:This method keeps a weak reference to the {@linkImageView} instance and will* automatically support object recycling.*/
public void into(ImageView target) {
into(target, null);
}
真正調用帶回調參數的方法。如果直接調用這個方法,註釋裏面提示也說明了,callback這個參數會是一個強引用,可能會導致阻止你的activity或者fragment被垃圾回收器回收.如果你調用這個方法,強烈建議你調用canlRequest阻止內存泄露.
/*** Asynchronously fulfills the request into the specified {@linkImageView} and invokes the* target {@linkCallback} if it's not {@codenull}.*
*Note:The {@linkCallback} param is a strong reference and will prevent your* {@linkandroid.app.Activity} or {@linkandroid.app.Fragment}
from being garbage collected. If* you use this method, it isstronglyrecommended you invoke an adjacent* {@linkPicasso#cancelRequest(android.widget.ImageView)} call to prevent temporary leaking.*/
public void into(ImageView target,Callback callback) {
longstarted = System.nanoTime();
checkMain();
if(target ==null) {
throw new IllegalArgumentException("Target must not be null.");
}
if(!data.hasImage()) {
picasso.cancelRequest(target);
if(setPlaceholder) {
setPlaceholder(target,getPlaceholderDrawable());
}
return;
}
if(deferred) {
if(data.hasSize()) {
throw new IllegalStateException("Fit cannot be used with resize.");
}
intwidth = target.getWidth();
intheight = target.getHeight();
if(width ==0|| height ==0|| target.isLayoutRequested()) {
if(setPlaceholder) {
setPlaceholder(target,getPlaceholderDrawable());
}
picasso.defer(target, newDeferredRequestCreator(this,target,callback));
return;
}
data.resize(width,height);
}
Request request = createRequest(started);
String requestKey =createKey(request);
if(shouldReadFromMemoryCache(memoryPolicy)) {
Bitmap bitmap =picasso.quickMemoryCacheCheck(requestKey);
if(bitmap !=null) {
picasso.cancelRequest(target);
setBitmap(target,picasso.context,bitmap,MEMORY,noFade,picasso.indicatorsEnabled);
if(picasso.loggingEnabled) {
log(OWNER_MAIN,VERB_COMPLETED,request.plainId(),"from "+MEMORY);
}
if(callback !=null) {
callback.onSuccess();
}
return;
}
}
if(setPlaceholder) {
setPlaceholder(target,getPlaceholderDrawable());
}
Action action =
new ImageViewAction(picasso,target,request,memoryPolicy,networkPolicy,errorResId,
errorDrawable,requestKey,tag,callback,noFade);
picasso.enqueueAndSubmit(action);
}
再分析
boolean hasImage() {
returnuri!=null||resourceId!=0;
}
如果沒有下載地址,又沒有資源id,取消請求,需要設置佔位背景圖片則設置佔位背景圖片
if(!data.hasImage()) {
picasso.cancelRequest(target);
if(setPlaceholder) {
setPlaceholder(target,getPlaceholderDrawable());
}
return;
}
設置佔位圖片背景就比較簡單了。
private Drawable getPlaceholderDrawable() {
if(placeholderResId!=0) {
return picasso.context.getResources().getDrawable(placeholderResId);
}else{
return placeholderDrawable;// This may be null which is expected and desired behavior.
}
}
後面如果設置是要處理下載的圖片大小.則deferred爲true .如果設置了
public RequestCreator fit() {
deferred=true;
return this;
}
此處爲false。則直接跳過
if(deferred) {
if(data.hasSize()) {
throw new IllegalStateException("Fit cannot be used with resize.");
}
intwidth = target.getWidth();
intheight = target.getHeight();
if(width ==0|| height ==0|| target.isLayoutRequested()) {
if(setPlaceholder) {
setPlaceholder(target,getPlaceholderDrawable());
}
picasso.defer(target, newDeferredRequestCreator(this,target,callback));
return;
}
data.resize(width,height);
}
生成一個request對象。根據request對象裏面的屬性又生成一個requestKey.首先判斷是否從內存中獲取,默認是有設置了內存緩存的,所以先從內存中獲取bitmap對象。如果有當前對象,則取消request請求.將bitmap設置到imageview上面去。
Request request = createRequest(started);
String requestKey =createKey(request);
if(shouldReadFromMemoryCache(memoryPolicy)) {
Bitmap bitmap =picasso.quickMemoryCacheCheck(requestKey);
if(bitmap !=null) {
picasso.cancelRequest(target);
setBitmap(target,picasso.context,bitmap,MEMORY,noFade,picasso.indicatorsEnabled);
if(picasso.loggingEnabled) {
log(OWNER_MAIN,VERB_COMPLETED,request.plainId(),"from "+MEMORY);
}
if(callback !=null) {
callback.onSuccess();
}
return;
}
}
如果緩存中沒有。先設置佔位背景。再生成一個action對象提交
if(setPlaceholder) {
setPlaceholder(target,getPlaceholderDrawable());
}
Action action =
new ImageViewAction(picasso,target,request,memoryPolicy,networkPolicy,errorResId,
errorDrawable,requestKey,tag,callback,noFade);
picasso.enqueueAndSubmit(action);
首先判斷當前action是否已經在列隊中,如果已經存在,則先取消。再重新放進去。最後調用submit。這裏這個target對象就是imageview對象。一個imageview對象和一個action對象保存在targetToAction Map集合當中。這裏這麼處理,就巧妙的解決了listview上下滑動時imageview對象複用時不會造成加載圖片亂序.舉個栗子,如果當期imageview還在加載圖片,這時listivew滑動造成imageview的不可見時重新複用,然後再去加載新的圖片時就會把前面未加載的圖片請求取消。
void enqueueAndSubmit(Action action) {
Object target = action.getTarget();
if(target !=null&&targetToAction.get(target) != action) {
// This will also check we are on the main thread.
cancelExistingRequest(target);
targetToAction.put(target,action);
}
submit(action);
}
提交action
void submit(Action action) {
dispatcher.dispatchSubmit(action);
}
僅發送一個請求
void dispatchSubmit(Action action) {
handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT,action));
}
handler裏面的處理
@Override
public void handleMessage(finalMessage msg) {
switch(msg.what) {
caseREQUEST_SUBMIT: {
Action action = (Action) msg.obj;
dispatcher.performSubmit(action);
break;
}
又調用
void performSubmit(Action action) {
performSubmit(action, true);
}
此方法比較重要,一一着重分析
void performSubmit(Action action, booleandismissFailed) {
if(pausedTags.contains(action.getTag())) {
pausedActions.put(action.getTarget(),action);
if(action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER,VERB_PAUSED,action.request.logId(),
"because tag '"+ action.getTag() +"' is paused");
}
return;
}
//如果當前已經有url對應的action在下載了(url和key一一對應,action和imageview一一對應,一個bitmapHunter可能對應多個action)
BitmapHunter hunter =hunterMap.get(action.getKey());
if(hunter !=null) {
hunter.attach(action);
return;
}
if(service.isShutdown()) {
if(action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER,VERB_IGNORED,action.request.logId(),"because shut down");
}
return;
}
hunter =forRequest(action.getPicasso(), this,cache,stats,action);
hunter.future=service.submit(hunter);
hunterMap.put(action.getKey(),hunter);
if(dismissFailed) {
failedActions.remove(action.getTarget());
}
if(action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER,VERB_ENQUEUED,action.request.logId());
}
}
首先在pausedTagsSet集合中查看是否存在imageview。(看這集合的名字,應該是暫停當前請求的集合),如果存在,則又在pausedActions map集合裏面放入對應的action。直接返回
if(pausedTags.contains(action.getTag())) {
pausedActions.put(action.getTarget(),action);
if(action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER,VERB_PAUSED,action.request.logId(),
"because tag '"+ action.getTag() +"' is paused");
}
return;
}
然後從hunterMap集合中根據action的key獲取一個BitmapHunter對象,BitmapHunter繼承Runable,可見應該最後從網絡獲取後生成bitmap處理的就是這個對象。
BitmapHunter hunter =hunterMap.get(action.getKey());
if(hunter !=null) {
hunter.attach(action);
return;
}
由於還沒有添加到hunterMap集合中,故這裏先拿到的是null。繼續往下走
判斷線程池是否關閉,如果關閉則直接返回。
if(service.isShutdown()) {
if(action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER,VERB_IGNORED,action.request.logId(),"because shut down");
}
return;
}
hunter =forRequest(action.getPicasso(), this,cache,stats,action);
hunter.future=service.submit(hunter);
hunterMap.put(action.getKey(),hunter);
if(dismissFailed) {
failedActions.remove(action.getTarget());
}
if(action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER,VERB_ENQUEUED,action.request.logId());
}
生成一個bitmapHunter。
staticBitmapHunterforRequest(Picasso picasso,Dispatcher dispatcher,Cache cache,Stats stats,
Action action) {
Request request = action.getRequest();
List requestHandlers = picasso.getRequestHandlers();
// Index-based loop to avoid allocating an iterator.
//noinspection ForLoopReplaceableByForEach
for(inti =0,count = requestHandlers.size();i < count;i++) {
RequestHandler requestHandler = requestHandlers.get(i);
if(requestHandler.canHandleRequest(request)) {
return newBitmapHunter(picasso,dispatcher,cache,stats,action,requestHandler);
}
}
return newBitmapHunter(picasso,dispatcher,cache,stats,action,ERRORING_HANDLER);
}
Picasso.getRequestHandlers()集合在picasso初始化的時候就添加了許多相應的RequestHandler。由名字可以看出如果是資源文件,則對象的是ResouceRequsetHandler處理,如果圖片在在SD卡,則會由FileRequestHandler處理,如果是URL,則由NetworkRequsetHandler處理。
allRequestHandlers.add(newResourceRequestHandler(context));
if(extraRequestHandlers !=null) {
allRequestHandlers.addAll(extraRequestHandlers);
}
allRequestHandlers.add(newContactsPhotoRequestHandler(context));
allRequestHandlers.add(newMediaStoreRequestHandler(context));
allRequestHandlers.add(newContentStreamRequestHandler(context));
allRequestHandlers.add(newAssetRequestHandler(context));
allRequestHandlers.add(newFileRequestHandler(context));
allRequestHandlers.add(newNetworkRequestHandler(dispatcher.downloader,stats));
requestHandlers= Collections.unmodifiableList(allRequestHandlers);
故這裏BitmapHunter傳入的就是NetworkRequestHandler對象。
然後把bitmapHunter提交到線程池.看PicassoExecutorSerice裏面的submit方法。PicassoFutureTask繼承了FutureTask,裏面包含了一個BitmapHunter
@Override
public Future submit(Runnable task) {
PicassoFutureTask ftask =new PicassoFutureTask((BitmapHunter) task);
execute(ftask);
returnftask;
}
再查看BitmapHunter裏面的run方法
public void run() {
try{
//根據Request更新當前線程名稱
updateThreadName(data);
if(picasso.loggingEnabled) {
log(OWNER_HUNTER,VERB_EXECUTING,getLogIdsForHunter(this));
}
result= hunt();
.....省略無關代碼
}
繼續hunt方法。依然判斷是否可以從緩存中獲取。默認是開啓的。首先依舊從緩存中獲取.如果有直接獲取。返回
Bitmaphunt() throws IOException {
Bitmap bitmap =null;
if(shouldReadFromMemoryCache(memoryPolicy)) {
bitmap =cache.get(key);
if(bitmap !=null) {
stats.dispatchCacheHit();
loadedFrom=MEMORY;
if(picasso.loggingEnabled) {
log(OWNER_HUNTER,VERB_DECODED,data.logId(),"from cache");
}
return bitmap;
}
}
。。。。後面代碼暫時省略
繼續後面的分析
Bitmaphunt() throws IOException {
Bitmap bitmap =null;
....省略前面分析過的代碼
networkPolicy=retryCount==0? NetworkPolicy.OFFLINE.index:networkPolicy;
RequestHandler.Result result =requestHandler.load(data,networkPolicy);
if(result !=null) {
loadedFrom= result.getLoadedFrom();
exifOrientation= result.getExifOrientation();
bitmap = result.getBitmap();
// If there was no Bitmap then we need to decode it from the stream.
if(bitmap ==null) {
Source source = result.getSource();
try{
bitmap =decodeStream(source,data);
}finally{
try{
//noinspection ConstantConditions If bitmap is null then source is guranteed non-null.
source.close();
}catch(IOException ignored) {
}
}
}
}
.....省略後面待分析的代碼
}
returnbitmap;
}
前面說了由於傳入的是個URL。所以requestHandler就是一個NetworkRequsetHandler對象。查看NetworkRequstHandler裏面的load方法,裏面的邏輯應該就是從網上下載圖片並且封裝成Result對象返回。
移步NetworkRequestHandler裏面的load方法.downloader就是picasso初始化的時候初始化的OkHttp3Downloader對象。OkHttp3Downloader裏面用到了OkHttp裏面的請求服務器的方法。具體不懂OkHttp的可以自行百度。獲取數據成功後封裝成Request返回
@Override
public Result load(Request request, intnetworkPolicy)throwsIOException {
okhttp3.Request downloaderRequest =createRequest(request,networkPolicy);
Response response =downloader.load(downloaderRequest);
ResponseBody body = response.body();
if(!response.isSuccessful()) {
body.close();
throw newResponseException(response.code(),request.networkPolicy);
}
// Cache response is only null when the response comes fully from the network. Both completely
// cached and conditionally cached responses will have a non-null cache response.
Picasso.LoadedFrom loadedFrom = response.cacheResponse() ==null?NETWORK:DISK;
// 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&& body.contentLength() ==0) {
body.close();
throw new ContentLengthException("Received response with 0 content-length header.");
}
if(loadedFrom ==NETWORK&& body.contentLength() >0) {
stats.dispatchDownloadFinished(body.contentLength());
}
return new Result(body.source(),loadedFrom);
}
然後調用decodeStream方法,把獲取的數據轉換爲bitmap對象,這裏
static Bitmap decodeStream(Source source,Request request)throwsIOException {
BufferedSource bufferedSource = Okio.buffer(source);
....省略代碼
// We decode from a byte array because, a) when decoding a WebP network stream, BitmapFactory
// throws a JNI Exception, so we workaround by decoding a byte array, or b) user requested
// purgeable, which only affects bitmaps decoded from byte arrays.
if(isWebPFile || isPurgeable) {
byte[] bytes = bufferedSource.readByteArray();
...省略一些是否計算options參數的代碼
//通過bytes獲取bitmap對象
returnBitmapFactory.decodeByteArray(bytes,0,bytes.length,options);
}else{
InputStream stream = bufferedSource.inputStream();
...省略一些是否計算options參數的代碼
//通過輸入流獲取bitmap對象
Bitmap bitmap = BitmapFactory.decodeStream(stream, null,options);
if(bitmap ==null) {
// (發現bitmap爲null,我們將最終重試)
//Treat null as an IO exception, we will eventually retry.
throw newIOException("Failed to decode stream.");
}
returnbitmap;
}
}
繼續看hunt方法.
Bitmaphunt() throws IOException {
Bitmap bitmap =null;
....省略前面分析過的代碼
if(bitmap !=null) {
if(picasso.loggingEnabled) {
log(OWNER_HUNTER,VERB_DECODED,data.logId());
}
stats.dispatchBitmapDecoded(bitmap);
if(data.needsTransformation() ||exifOrientation!=0) {
synchronized(DECODE_LOCK) {
if(data.needsMatrixTransform() ||exifOrientation!=0) {
bitmap =transformResult(data,bitmap,exifOrientation);
if(picasso.loggingEnabled) {
log(OWNER_HUNTER,VERB_TRANSFORMED,data.logId());
}
}
if(data.hasCustomTransformations()) {
bitmap =applyCustomTransformations(data.transformations,bitmap);
if(picasso.loggingEnabled) {
log(OWNER_HUNTER,VERB_TRANSFORMED,data.logId(),"from custom transformations");
}
}
}
if(bitmap !=null) {
stats.dispatchBitmapTransformed(bitmap);
}
}
}
return bitmap;
}
判斷如果需要作旋轉和縮放操作,則進入transformResult方法處理後返回bitmap.此方法代碼好長,有一大堆的數學方法處理,有興趣的童鞋自行研究。當然如果picasso裏面的轉換不能滿足,也可以自己自定義,只要實現Transformation方法即可。
hunt方法分析完畢。繼續回到run方法裏面
@Override
public void run() {
try{
updateThreadName(data);
if(picasso.loggingEnabled) {
log(OWNER_HUNTER,VERB_EXECUTING,getLogIdsForHunter(this));
}
result= hunt();
if(result==null) {
dispatcher.dispatchFailed(this);//獲取失敗了
}else{
dispatcher.dispatchComplete(this);//獲取成功了
}
......省略一些無關代碼
}
查看Dispater的dispatchCompleter方法。dispatchFailed方法類似
void dispatchComplete(BitmapHunter hunter) {
handler.sendMessage(handler.obtainMessage(HUNTER_COMPLETE,hunter));
}
查看handler處理
caseHUNTER_COMPLETE: {
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performComplete(hunter);
break;
}
performComplete方法。獲取bitmap完成後就寫入內存緩存.移除當前hunterMap集合中hunter對應的key。然後調用了batch方法
void performComplete(BitmapHunter hunter) {
if(shouldWriteToMemoryCache(hunter.getMemoryPolicy())) {
cache.set(hunter.getKey(),hunter.getResult());//寫入緩存
}
hunterMap.remove(hunter.getKey());
batch(hunter);
if(hunter.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER,VERB_BATCHED,getLogIdsForHunter(hunter),"for completion");
}
}
batch方法
private void batch(BitmapHunter hunter) {
if(hunter.isCancelled()) {
return;
}
if(hunter.result!=null) {
hunter.result.prepareToDraw();
}
batch.add(hunter);
if(!handler.hasMessages(HUNTER_DELAY_NEXT_BATCH)) {
handler.sendEmptyMessageDelayed(HUNTER_DELAY_NEXT_BATCH,BATCH_DELAY);
}
}
延遲200ms發送一個空消息
caseHUNTER_DELAY_NEXT_BATCH: {
dispatcher.performBatchComplete();
break;
}
performBatchComplete方法,複製到了一個copy集合中,發送一個消息到主線程的handler裏面
void performBatchComplete() {
List copy =newArrayList<>(batch);
batch.clear();
mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(HUNTER_BATCH_COMPLETE,copy));
logBatch(copy);
}
移步到Picasso裏面的主線程handler裏面
caseHUNTER_BATCH_COMPLETE: {
@SuppressWarnings("unchecked") List batch = (List) msg.obj;
//noinspection ForLoopReplaceableByForEach
for(inti =0,n = batch.size();i < n;i++) {
BitmapHunter hunter = batch.get(i);
hunter.picasso.complete(hunter);
}
break;
}
調用Picasso的complete方法
void complete(BitmapHunter hunter) {
Action single = hunter.getAction();
List joined = hunter.getActions();
booleanhasMultiple = joined !=null&& !joined.isEmpty();
booleanshouldDeliver = single !=null|| hasMultiple;
//如果加載成功single則不爲null,shouldDeliver爲true
if(!shouldDeliver) {
return;
}
Uri uri = hunter.getData().uri;
Exception exception = hunter.getException();
Bitmap result = hunter.getResult();
LoadedFrom from = hunter.getLoadedFrom();
if(single !=null) {
deliverAction(result,from,single,exception);
}
if(hasMultiple) {
//noinspection ForLoopReplaceableByForEach
//如果一個url對應幾個imageview控件,則一一設置
for(inti =0,n = joined.size();i < n;i++) {
Action join = joined.get(i);
deliverAction(result,from,join,exception);
}
}
if(listener!=null&& exception !=null) {
listener.onImageLoadFailed(this,uri,exception);
}
}
然後調用deliverAction方法
private voiddeliverAction(Bitmap result,LoadedFrom from,Action action,Exception e) {
//如果已經取消了
if(action.isCancelled()) {
return;
}
if(!action.willReplay()) {
targetToAction.remove(action.getTarget());
}
if(result !=null) {
if(from ==null) {
throw newAssertionError("LoadedFrom cannot be null.");
}
action.complete(result,from);
if(loggingEnabled) {
log(OWNER_MAIN,VERB_COMPLETED,action.request.logId(),"from "+ from);
}
}else{
action.error(e);
if(loggingEnabled) {
log(OWNER_MAIN,VERB_ERRORED,action.request.logId(),e.getMessage());
}
}
}
回調ImageViewAction裏面的相關方法。這裏着重看complete方法
@Override
public void complete(Bitmap result,Picasso.LoadedFrom from) {
if(result ==null) {
throw newAssertionError(
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;
booleanindicatorsEnabled =picasso.indicatorsEnabled;
//設置到bitmap到imageview上
PicassoDrawable.setBitmap(target,context,result,from,noFade,indicatorsEnabled);
//回調
if(callback!=null) {
callback.onSuccess();
}
}
最終調用PicassoDrawable裏面的setBitmap方法
static void setBitmap(ImageView target,Context context,Bitmap bitmap,
Picasso.LoadedFrom loadedFrom, boolean noFade, boolean debugging) {
Drawable placeholder = target.getDrawable();
if(placeholderinstanceofAnimationDrawable) {
((AnimationDrawable) placeholder).stop();
}
PicassoDrawable drawable =
new PicassoDrawable(context,bitmap,placeholder,loadedFrom,noFade,debugging);
target.setImageDrawable(drawable);
}
至此完成