Picasso源码分析

首先从调用第一行代码看起

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

}

至此完成

阅读更多
个人分类: android 源码解读
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭