概述
前面分析了Volley的源碼,現(xiàn)在來(lái)看一下Picasso的源碼,其實(shí)Volley已經(jīng)具備了加載了網(wǎng)絡(luò)圖片的功能,只是性能不是很好,Picasso是Square公司推出的一款圖片加載框架,只能加載圖片,所以性能肯定會(huì)比Volley好,Picasso的很多設(shè)計(jì)實(shí)際上跟Volley很相似,后來(lái)看到Picasso中的一個(gè)類BitmapHunter的注釋,發(fā)現(xiàn)其實(shí)Picasso的作者也是參考了Volley的一些設(shè)計(jì)的。
Global lock for bitmap decoding to ensure that we are only are decoding one at a time. Since this will only ever happen in background threads we help avoid excessive memory thrashing as well as potential OOMs. Shamelessly stolen from Volley.
當(dāng)時(shí)看到注釋的最后一句就笑了,牛逼的框架也都是一步一步完善起來(lái)的,不過(guò)很佩服Picasso的作者,還在注釋中說(shuō)出來(lái),也是沒(méi)誰(shuí)了,下面總結(jié)一下Picasso的設(shè)計(jì)原理。

Picasso大致的可以分這幾大塊,其實(shí)也比較好理解,如果我們只是加載一張圖片,那么很自然的可以連工具類都不用寫,用HttpUrlConnection或者用OkhttoUrlConnection去讀流,然后進(jìn)行轉(zhuǎn)碼,適當(dāng)?shù)谋壤s放就可以加載一張圖片,框架無(wú)非就是為了提高代碼的復(fù)用性以及加載速度,加載性能,不然也不會(huì)有人去寫去用,對(duì)于Bitmap,有一點(diǎn)需要注意的就是OOM,然后結(jié)合以上節(jié)點(diǎn),就是大部分框架需要考慮的東西。
正文
加載流程
先來(lái)看Picasso是如何調(diào)用的
Picasso.get()//獲取Picasso單例
.load("url")//RequestCreator配置url,返回RequestCreator
.placeholder(R.mipmap.ic_launcher)//RequestCreator配置占位圖,返回RequestCreator
.error(R.mipmap.ic_launcher)//RequestCreator配置失敗的占位圖,返回RequestCreator
.fit()//自動(dòng)縮放圖片,返回RequestCreator
.into(new ImageView(this));//開(kāi)始加載圖片
這個(gè)是在Github上面的最新的demo里面,已經(jīng)用get代替了之前的with方法這里并沒(méi)有去畫流程圖或者類圖,感覺(jué)太大必要,因?yàn)樽约簩戇^(guò)簡(jiǎn)單的圖片加載框架,前面也分析過(guò)Volley的源碼,整體的流程都是大同小異的,對(duì)于Picasso而言,依然是先配置一些基本信息,緩存策略,占位圖等,然后就開(kāi)始根據(jù)緩存策略進(jìn)行數(shù)據(jù)讀取,所以,不再贅述,打算就Picasso的一些核心類進(jìn)行重點(diǎn)分析。
get方法
static volatile Picasso singleton = null;
public static Picasso get() {
if (singleton == null) {
synchronized (Picasso.class) {
http:
if (singleton == null) {
if (PicassoProvider.context == null) {
throw new IllegalStateException("context == null");
}
singleton = new Builder(PicassoProvider.context).build();
}
}
}
return singleton;
}
由于此方法是會(huì)在多線程中經(jīng)常被調(diào)用的,所以為了保證線程安全,采用了雙重檢查,其實(shí)我們也可以用靜態(tài)內(nèi)部類的形式來(lái)替代如下:
private static class NestedPicasso {
public static Picasso singleton;
static {
System.out.println("instance = new SingletonTest()");
if (PicassoProvider.context == null) {
throw new IllegalStateException("context == null");
}
singleton = new Builder(PicassoProvider.context).build();
}
}
public static Picasso get() {
return NestedPicasso.singleton;
}
into
public void into(ImageView target, Callback callback) {
long started = System.nanoTime();
checkMain();//檢測(cè)是否在主線程
if (target == null) {
throw new IllegalArgumentException("Target must not be null.");
}
if (!data.hasImage()) {
//判斷是否傳入了圖片的加載地址
picasso.cancelRequest(target);
if (setPlaceholder) {
//如果設(shè)置了占位圖,就進(jìn)行占位圖設(shè)置
setPlaceholder(target, getPlaceholderDrawable());
}
return;
}
if (deferred) {
//fit操作跟resize不能同時(shí)存在,這個(gè)也很好理解,
//要么根據(jù)ImageView自己的尺寸要么根據(jù)我傳入的尺寸,魚(yú)跟熊掌不可兼得
if (data.hasSize()) {
throw new IllegalStateException("Fit cannot be used with resize.");
}
int width = target.getWidth();
int height = target.getHeight();
if (width == 0 || height == 0 || target.isLayoutRequested()) {
//如果ImageView的寬高有一個(gè)為0,也就是wrap的情況那么就必須延遲加載
if (setPlaceholder) {
//設(shè)置占位圖
setPlaceholder(target, getPlaceholderDrawable());
}
// 在DeferredRequestCreator重新測(cè)量
picasso.defer(target, new DeferredRequestCreator(this, target, callback));
return;
}
//對(duì)重新設(shè)置ImageView的尺寸
data.resize(width, height);
}
Request request = createRequest(started);//創(chuàng)建一個(gè)請(qǐng)求
String requestKey = createKey(request);//創(chuàng)建緩存的key
if (shouldReadFromMemoryCache(memoryPolicy)) {
//如果需要從緩存中讀取,則查找內(nèi)存緩存
Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
if (bitmap != null) {
//獲取到緩存,取消掉請(qǐng)求
picasso.cancelRequest(target);
//設(shè)置Bitmap給ImageView
setBitmap(target, picasso.context, bitmap, MEMORY, noFade,picasso.indicatorsEnabled);
if (picasso.loggingEnabled) {
log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY);
}
if (callback != null) {
//成功的回調(diào)
callback.onSuccess();
}
return;
}
}
if (setPlaceholder) {
//設(shè)置占位圖
setPlaceholder(target, getPlaceholderDrawable());
}
//創(chuàng)建ImageViewAction
Action action = new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,errorDrawable, requestKey, tag, callback, noFade);
//Action入隊(duì)
picasso.enqueueAndSubmit(action);
}
enqueueAndSubmit之后經(jīng)過(guò)一系列調(diào)用,最終調(diào)用了Diapatcher的performSubmit
performSubmit
void performSubmit(Action action, boolean dismissFailed) {
//如果之前是pause過(guò),那么調(diào)用resume
if (pausedTags.contains(action.getTag())) {
pausedActions.put(action.getTarget(), action);
return;
}
//通過(guò)Key獲取BitmapHunter
BitmapHunter hunter = hunterMap.get(action.getKey());
if (hunter != null) {
//將action添加進(jìn)BitmapHunter
hunter.attach(action);
return;
}
if (service.isShutdown()) {
//如果線程池關(guān)閉,直接返回
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
}
return;
}
//創(chuàng)建一個(gè)BitmapHunter
hunter = forRequest(action.getPicasso(), this, cache, stats, action);
//拿到線程池執(zhí)行的結(jié)果,BitmapHunter肯定是個(gè)Runnable或者Future
hunter.future = service.submit(hunter);
//存入map中
hunterMap.put(action.getKey(), hunter);
if (dismissFailed) {
failedActions.remove(action.getTarget());
}
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
}
}
我們知道把BitmapHunter放進(jìn)了線程池,而B(niǎo)itmapHunter是個(gè)Runnable,那么所有的耗時(shí)操作肯定是放在run方法,追蹤之后執(zhí)行的是hunt方法,那么就來(lái)看一下hunt的具體流程
hunt
Bitmap hunt() throws IOException {
Bitmap bitmap = null;
if (shouldReadFromMemoryCache(memoryPolicy)) {
//再次讀取內(nèi)存緩存,因?yàn)椴煌恼?qǐng)求優(yōu)先級(jí)不一樣,很可能等到真正執(zhí)行的時(shí)候
//當(dāng)前的url已經(jīng)被緩存了
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;
}
}
networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy;
//如果沒(méi)有讀取緩存或者緩存讀取失敗,就開(kāi)始真正的請(qǐng)求
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 {
source.close();
} catch (IOException ignored) {
}
}
}
}
if (bitmap != null) {
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_DECODED, data.logId());
}
stats.dispatchBitmapDecoded(bitmap);
//看看是否需要進(jìn)行變換前預(yù)處理,有的話就處理
if (data.needsTransformation() || exifOrientation != 0) {
synchronized (DECODE_LOCK) {
//通過(guò)上鎖,每次只有一個(gè)進(jìn)行Decodeing
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 (bitmap != null) {
stats.dispatchBitmapTransformed(bitmap);
}
}
}
return bitmap;
}
接下來(lái)的就是將Bitmap回傳給ImageView了,還是在Dispatcher中,調(diào)用了performRequest方法
void performComplete(BitmapHunter hunter) {
if (shouldWriteToMemoryCache(hunter.getMemoryPolicy())) {
cache.set(hunter.getKey(), hunter.getResult());
}
hunterMap.remove(hunter.getKey());
batch(hunter);//追蹤Bitmap
}
拿到數(shù)據(jù),在這里還是在工作線程里面,由于需要在主線程進(jìn)行顯示ImageView,所以需要切換線程,這里用到了 初始化的Handler,也就是通過(guò)MainLooper初始化
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);
}
}
主線程拿到傳遞過(guò)來(lái)的消息之后,經(jīng)過(guò)中轉(zhuǎn),最后還是到了ImageViewAction中,最終調(diào)用了complete方法
complete
@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;
//設(shè)置Bitmap
PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);
if (callback != null) {
callback.onSuccess();
}
}
繼續(xù)看setBitmap
setBitmap
static void setBitmap(ImageView target, Context context, Bitmap bitmap,
Picasso.LoadedFrom loadedFrom, boolean noFade, boolean debugging) {
Drawable placeholder = target.getDrawable();
if (placeholder instanceof Animatable) {
((Animatable) placeholder).stop();
}
PicassoDrawable drawable =
new PicassoDrawable(context, bitmap, placeholder, loadedFrom, noFade, debugging);
//最終設(shè)置的是一個(gè)BitmapDrawable
target.setImageDrawable(drawable);
}
所以最終設(shè)置給ImageView的不是Bitmap,而是一個(gè)BitmapDrawable,我們看一下setImagBitmap的源碼
public void setImageBitmap(Bitmap bm) {
// Hacky fix to force setImageDrawable to do a full setImageDrawable
// instead of doing an object reference comparison
mDrawable = null;
if (mRecycleableBitmapDrawable == null) {
mRecycleableBitmapDrawable = new BitmapDrawable(mContext.getResources(), bm);
} else {
mRecycleableBitmapDrawable.setBitmap(bm);
}
//也是調(diào)用了setImageDrawable
setImageDrawable(mRecycleableBitmapDrawable);
}
之所以設(shè)置的是BitmapDrawable,有兩個(gè)原因,一個(gè)是為了展示加載的動(dòng)畫,另一個(gè)是在debug模式下面可以繪制右上角的三角調(diào)試符號(hào),這些都是在初始化BitmapDrawable的時(shí)候加進(jìn)去的。
通過(guò)追蹤源碼的方式,可以了解到Picasso整體加載流程,有很多細(xì)節(jié)沒(méi)有分析到,不過(guò)我們已經(jīng)知道了,在分析過(guò)程中涉及到了很多類,其中有幾個(gè)類是反復(fù)出現(xiàn)的,Picasso,RequestCreator,Dispatcher,RequestHandler,Action,另外還有一些類,比如說(shuō)PicassoDrawable,LruCache,OkHttp3Downloader等,下面重點(diǎn)分析一下。
Picasso
成員變量
//清理線程,主要是用來(lái)清理ImageView被回收了的Request
private final CleanupThread cleanupThread;
//存放RequestHandler的集合
private final List<RequestHandler> requestHandlers;
//分發(fā)的一個(gè)關(guān)鍵類,主要用來(lái)轉(zhuǎn)發(fā)各種請(qǐng)求結(jié)果
final Dispatcher dispatcher;
//緩存
final Cache cache;
//存放不同Action的Map
final Map<Object, Action> targetToAction;
//存放延遲加載的RequestCreator,也就是fit狀態(tài)下獲取的寬或者為高的ImageView
final Map<ImageView, DeferredRequestCreator> targetToDeferredRequestCreator;
//引用隊(duì)列,每隔一段時(shí)間獲取被回收的target
final ReferenceQueue<Object> referenceQueue;
Picasso這個(gè)類持有了成員變量requestHandler集合,Action集合,Dispatcher,Cache這幾個(gè)前面提到的核心類,所以它自己實(shí)際上沒(méi)有什么特殊的功能,只是在間接的調(diào)用了這些核心類的功能,實(shí)際上是一個(gè)裝飾者模式,暴露給外部調(diào)用者調(diào)用,這也是為什么Picasso使用起來(lái)很簡(jiǎn)潔,原因就在于Picasso在這個(gè)類,封裝了所有的方法。
構(gòu)造方法
Picasso(Context context, Dispatcher dispatcher, Cache cache, Listener listener,
RequestTransformer requestTransformer,
List<RequestHandler> extraRequestHandlers,
Stats stats,Bitmap.Config defaultBitmapConfig,
boolean indicatorsEnabled,
boolean loggingEnabled) {
this.context = context;
this.dispatcher = dispatcher;
this.cache = cache;
this.listener = listener;
this.requestTransformer = requestTransformer;
this.defaultBitmapConfig = defaultBitmapConfig;
int builtInHandlers = 7;
int extraCount = (extraRequestHandlers != null ? extraRequestHandlers.size() : 0);
List<RequestHandler> allRequestHandlers = new ArrayList<>(builtInHandlers + extraCount);
allRequestHandlers.add(new ResourceRequestHandler(context));
if (extraRequestHandlers != null) {
allRequestHandlers.addAll(extraRequestHandlers);
}
//初始化所有的圖片讀取Handler
allRequestHandlers.add(new ContactsPhotoRequestHandler(context));
allRequestHandlers.add(new MediaStoreRequestHandler(context));
allRequestHandlers.add(new ContentStreamRequestHandler(context));
allRequestHandlers.add(new AssetRequestHandler(context));
allRequestHandlers.add(new FileRequestHandler(context));
allRequestHandlers.add(new NetworkRequestHandler(dispatcher.downloader, stats));
requestHandlers = Collections.unmodifiableList(allRequestHandlers);
this.targetToAction = new WeakHashMap<>();//軟引用的Map
this.targetToDeferredRequestCreator = new WeakHashMap<>();//軟引用的Map
}
Builder
public static class Builder {
private final Context context;
private Downloader downloader;
private ExecutorService service;
private Cache cache;
private Listener listener;
private RequestTransformer transformer;
private List<RequestHandler> requestHandlers;
private Bitmap.Config defaultBitmapConfig;
private boolean indicatorsEnabled;
private boolean loggingEnabled;
//構(gòu)造Builder對(duì)象
public Builder(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("Context must not be null.");
}
this.context = context.getApplicationContext();
}
//配置默認(rèn)信息
public Builder defaultBitmapConfig(@NonNull Bitmap.Config bitmapConfig) {
if (bitmapConfig == null) {
throw new IllegalArgumentException("Bitmap config must not be null.");
}
this.defaultBitmapConfig = bitmapConfig;
return this;
}
//配置下載器
public Builder downloader(@NonNull Downloader downloader) {
if (downloader == null) {
throw new IllegalArgumentException("Downloader must not be null.");
}
if (this.downloader != null) {
throw new IllegalStateException("Downloader already set.");
}
this.downloader = downloader;
return this;
}
//配置線程池
public Builder executor(@NonNull ExecutorService executorService) {
if (executorService == null) {
throw new IllegalArgumentException("Executor service must not be null.");
}
if (this.service != null) {
throw new IllegalStateException("Executor service already set.");
}
this.service = executorService;
return this;
}
//配置內(nèi)存緩存策略
public Builder memoryCache(@NonNull Cache memoryCache) {
if (memoryCache == null) {
throw new IllegalArgumentException("Memory cache must not be null.");
}
if (this.cache != null) {
throw new IllegalStateException("Memory cache already set.");
}
this.cache = memoryCache;
return this;
}
//配置回調(diào)接庫(kù)
public Builder listener(@NonNull Listener listener) {
if (listener == null) {
throw new IllegalArgumentException("Listener must not be null.");
}
if (this.listener != null) {
throw new IllegalStateException("Listener already set.");
}
this.listener = listener;
return this;
}
//請(qǐng)求轉(zhuǎn)換器
public Builder requestTransformer(@NonNull RequestTransformer transformer) {
if (transformer == null) {
throw new IllegalArgumentException("Transformer must not be null.");
}
if (this.transformer != null) {
throw new IllegalStateException("Transformer already set.");
}
this.transformer = transformer;
return this;
}
//添加請(qǐng)求處理器
public Builder addRequestHandler(@NonNull RequestHandler requestHandler) {
if (requestHandler == null) {
throw new IllegalArgumentException("RequestHandler must not be null.");
}
if (requestHandlers == null) {
requestHandlers = new ArrayList<>();
}
if (requestHandlers.contains(requestHandler)) {
throw new IllegalStateException("RequestHandler already registered.");
}
requestHandlers.add(requestHandler);
return this;
}
//指示器開(kāi)關(guān)
public Builder indicatorsEnabled(boolean enabled) {
this.indicatorsEnabled = enabled;
return this;
}
//日志開(kāi)關(guān)
public Builder loggingEnabled(boolean enabled) {
this.loggingEnabled = enabled;
return this;
}
//構(gòu)造Picasso
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;
}
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);
}
}
由于Picasso的配置信息很多,所以采用的是Builder模式,所以跟大多數(shù)框架一樣,采用了建造者模式進(jìn)行構(gòu)造的。
cancelTag
通過(guò)tag取消請(qǐng)求
public void cancelTag(@NonNull Object tag) {
checkMain();
if (tag == null) {
throw new IllegalArgumentException("Cannot cancel requests with null tag.");
}
List<Action> actions = new ArrayList<>(targetToAction.values());
//遍歷所有的Action,如果找到該tag,則進(jìn)行取消
for (int i = 0, n = actions.size(); i < n; i++) {
Action action = actions.get(i);
if (tag.equals(action.getTag())) {
//取消請(qǐng)求
cancelExistingRequest(action.getTarget());
}
}
List<DeferredRequestCreator> deferredRequestCreators =
new ArrayList<>(targetToDeferredRequestCreator.values());
//取消需要重新測(cè)量的deferredRequestCreator
for (int i = 0, n = deferredRequestCreators.size(); i < n; i++) {
DeferredRequestCreator deferredRequestCreator = deferredRequestCreators.get(i);
if (tag.equals(deferredRequestCreator.getTag())) {
deferredRequestCreator.cancel();
}
}
}
繼續(xù)看cancelExistingRequest
void cancelExistingRequest(Object target) {
checkMain();
Action action = targetToAction.remove(target);
if (action != null) {
//取消Action
action.cancel();
//取消BitmapHunter中的Action,一會(huì)兒再看Action中分析
dispatcher.dispatchCancel(action);
}
if (target instanceof ImageView) {
ImageView targetImageView = (ImageView) target;
DeferredRequestCreator deferredRequestCreator =
targetToDeferredRequestCreator.remove(targetImageView);
if (deferredRequestCreator != null) {
//取消延遲加載的請(qǐng)求
deferredRequestCreator.cancel();
}
}
}
enqueueAndSubmit
void enqueueAndSubmit(Action action) {
Object target = action.getTarget();
if (target != null && targetToAction.get(target) != action) {
cancelExistingRequest(target);
targetToAction.put(target, action);
}
//提交請(qǐng)求
submit(action);
}
resumeAction
void resumeAction(Action action) {
Bitmap bitmap = null;
//從內(nèi)存中進(jìn)行讀取
if (shouldReadFromMemoryCache(action.memoryPolicy)) {
bitmap = quickMemoryCacheCheck(action.getKey());
}
if (bitmap != null) {
// 內(nèi)存讀取成功,完成整個(gè)流程
deliverAction(bitmap, LoadedFrom.MEMORY, action, null);
} else {
// 重新加入隊(duì)列
enqueueAndSubmit(action);
if (loggingEnabled) {
log(OWNER_MAIN, VERB_RESUMED, action.request.logId());
}
}
}
handler
//主線程中創(chuàng)建
static final Handler HANDLER = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case HUNTER_BATCH_COMPLETE: {
//請(qǐng)求完成
@SuppressWarnings("unchecked")
List<BitmapHunter> batch = (List<BitmapHunter>) msg.obj;
for (int i = 0, n = batch.size(); i < n; i++) {
BitmapHunter hunter = batch.get(i);
hunter.picasso.complete(hunter);
}
break;
}
//GC回收的ImageView
case REQUEST_GCED: {
Action action = (Action) msg.obj;
action.picasso.cancelExistingRequest(action.getTarget());
break;
}
//請(qǐng)求恢復(fù)
case REQUEST_BATCH_RESUME:
for (int i = 0, n = batch.size(); i < n; i++) {
Action action = batch.get(i);
action.picasso.resumeAction(action);
}
break;
default:
throw new AssertionError("Unknown handler message received: " + msg.what);
}
}
};
load
加載的資源路徑
//加載路徑
public RequestCreator load(@Nullable String 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));
}
//加載文件
public RequestCreator load(@NonNull File file) {
if (file == null) {
return new RequestCreator(this, null, 0);
}
return load(Uri.fromFile(file));
}
//加載資源id
public RequestCreator load(@DrawableRes int resourceId) {
if (resourceId == 0) {
throw new IllegalArgumentException("Resource ID must not be zero.");
}
return new RequestCreator(this, null, resourceId);
}
load有很多重載方法,可以用來(lái)加載網(wǎng)絡(luò)url,讀取文件,讀取資源id,返回的是RequestCreator
pauseTag
暫停請(qǐng)求
*/
public void pauseTag(@NonNull Object tag) {
if (tag == null) {
throw new IllegalArgumentException("tag == null");
}
//diapatcher轉(zhuǎn)發(fā)
dispatcher.dispatchPauseTag(tag);
}
resumeTag
public void resumeTag(@NonNull Object tag) {
if (tag == null) {
throw new IllegalArgumentException("tag == null");
}
//diapatcher轉(zhuǎn)發(fā)
dispatcher.dispatchResumeTag(tag);
}
quickMemoryCacheCheck
Bitmap quickMemoryCacheCheck(String key) {
Bitmap cached = cache.get(key);
if (cached != null) {
stats.dispatchCacheHit();
} else {
stats.dispatchCacheMiss();
}
return cached;
}
complete
void complete(BitmapHunter hunter) {
Action single = hunter.getAction();
List<Action> joined = hunter.getActions();
boolean hasMultiple = joined != null && !joined.isEmpty();
boolean shouldDeliver = single != null || hasMultiple;
if (!shouldDeliver) {
return;
}
Uri uri = hunter.getData().uri;
Exception exception = hunter.getException();
Bitmap result = hunter.getResult();
LoadedFrom from = hunter.getLoadedFrom();
if (single != null) {
//轉(zhuǎn)發(fā)請(qǐng)求
deliverAction(result, from, single, exception);
}
if (hasMultiple) {
//多個(gè)Action,依次遍歷轉(zhuǎn)發(fā)
for (int i = 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);
}
}
shutDown
public void shutdown() {
if (this == singleton) {
throw new UnsupportedOperationException("Default singleton instance cannot be shutdown.");
}
if (shutdown) {
return;
}
cache.clear(); //清空緩存
cleanupThread.shutdown();//清理引用隊(duì)列
stats.shutdown();//關(guān)閉統(tǒng)計(jì)
dispatcher.shutdown(); //關(guān)閉Dispatcher
//取消所有延遲加載的請(qǐng)求
for (DeferredRequestCreator deferredRequestCreator:targetToDeferredRequestCreator.values()) {
deferredRequestCreator.cancel();
}
targetToDeferredRequestCreator.clear();
shutdown = true;
}
RequestHandler
繼承關(guān)系

RequestHandler有很多子類,這些是實(shí)際上進(jìn)行網(wǎng)絡(luò)請(qǐng)求的處理器,使用最多的是NetworkRequestHandler,其核心方法是load,主要交給子類實(shí)現(xiàn),看一下NetworkRequestHandler的實(shí)現(xiàn):
@Override
public Result load(Request request, int networkPolicy) throws IOException {
//采用最新版的Okhttp3進(jìn)行網(wǎng)絡(luò)請(qǐng)求
okhttp3.Request downloaderRequest = createRequest(request, networkPolicy);
//獲取網(wǎng)絡(luò)返回的結(jié)果
Response response = downloader.load(downloaderRequest);
ResponseBody body = response.body();
//省略若干代碼
//判斷數(shù)據(jù)結(jié)果是來(lái)源于網(wǎng)絡(luò)還是磁盤
Picasso.LoadedFrom loadedFrom = response.cacheResponse() == null ? NETWORK : DISK;
return new Result(body.source(), loadedFrom);
}
這里其實(shí)有一點(diǎn)需要注意的就是,我們?cè)赑icasso包下并沒(méi)有發(fā)現(xiàn)磁盤緩存,只有LruCache這個(gè)類,也就是通常所說(shuō)的內(nèi)存緩存,但是并沒(méi)有磁盤緩存,實(shí)際上Picasso的緩存全部交給了OKhttp來(lái)實(shí)現(xiàn)了,默認(rèn)的緩存路徑是由Utils生成的,PICASSO_CACHE的值picasso-cache
static File createDefaultCacheDir(Context context) {
File cache = new File(context.getApplicationContext().getCacheDir(), PICASSO_CACHE);
if (!cache.exists()) {
cache.mkdirs();
}
return cache;
}
成員變量
private static final AtomicInteger nextId = new AtomicInteger();//請(qǐng)求ID
private final Picasso picasso;//Picasso引用
private final Request.Builder data;//builder構(gòu)造對(duì)象
private boolean noFade;//開(kāi)啟加載動(dòng)畫
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;//請(qǐng)求的tag
很簡(jiǎn)單,除了Picasso之外,沒(méi)有持有其它核心類的引用
構(gòu)造方法
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;
//不管是傳入的什么參數(shù),Picasso最后都是通過(guò)Uri來(lái)進(jìn)行構(gòu)造的,這樣就需要針對(duì)不同的加載類型
//來(lái)實(shí)現(xiàn)重載了
this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);
}
Builder模式
參數(shù)Builder
//通過(guò)Uri構(gòu)造
public Builder(@NonNull Uri uri) {
setUri(uri);
}
//通過(guò)資源ID構(gòu)造
public Builder(@DrawableRes int resourceId) {
setResourceId(resourceId);
}
//同時(shí)傳入U(xiǎn)ri,資源ID,BitmapConfig
Builder(Uri uri, int resourceId, Bitmap.Config bitmapConfig) {
this.uri = uri;
this.resourceId = resourceId;
this.config = bitmapConfig;
}
Request構(gòu)造
private Builder(Request request) {
uri = request.uri;
resourceId = request.resourceId;
stableKey = request.stableKey;
targetWidth = request.targetWidth;
targetHeight = request.targetHeight;
centerCrop = request.centerCrop;
centerInside = request.centerInside;
centerCropGravity = request.centerCropGravity;
rotationDegrees = request.rotationDegrees;
rotationPivotX = request.rotationPivotX;
rotationPivotY = request.rotationPivotY;
hasRotationPivot = request.hasRotationPivot;
purgeable = request.purgeable;
onlyScaleDown = request.onlyScaleDown;
if (request.transformations != null) {
transformations = new ArrayList<>(request.transformations);
}
config = request.config;
priority = request.priority;
}
fit方法
自適應(yīng)ImageView的尺寸
public RequestCreator fit() {
deferred = true;
return this;
}
resize
重設(shè)尺寸
public Builder resize(@Px int targetWidth, @Px int targetHeight) {
if (targetWidth < 0) {
throw new IllegalArgumentException("Width must be positive number or 0.");
}
if (targetHeight < 0) {
throw new IllegalArgumentException("Height must be positive number or 0.");
}
if (targetHeight == 0 && targetWidth == 0) {
throw new IllegalArgumentException("At least one dimension has to be positive number.");
}
this.targetWidth = targetWidth;
this.targetHeight = targetHeight;
return this;
}
屬性配置
public Builder centerCrop(int alignGravity) {
if (centerInside) {
throw new IllegalStateException("Center crop can not be used after calling centerInside");
}
centerCrop = true;
centerCropGravity = alignGravity;
return this;
}
public Builder clearCenterCrop() {
centerCrop = false;
centerCropGravity = Gravity.CENTER;
return this;
}
public Builder centerInside() {
if (centerCrop) {
throw new IllegalStateException("Center inside can not be used after calling centerCrop");
}
centerInside = true;
return this;
}
Action
Action是一個(gè)包裝類,會(huì)對(duì)我們的加載行為進(jìn)行一次包裝,包含了加載的信息以及回調(diào),先看一下它的繼承關(guān)系
繼承關(guān)系

Action跟RequestHandler一樣,有很多子類,不過(guò)很常見(jiàn)的一個(gè)是ImageViewAction,一會(huì)兒會(huì)重點(diǎn)分析一下
成員變量
final Picasso picasso;
final Request request;
final WeakReference<T> target;
final boolean noFade;
final int memoryPolicy;
final int networkPolicy;
final int errorResId;
final Drawable errorDrawable;
final String key;
final Object tag;
包含了picasso,request以及target的弱引用
構(gòu)造方法
Action(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<>(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);
}
下面看一下它的兩個(gè)方法,一個(gè)是complete一個(gè)是error方法,由于父類是抽象方法,所以只能交給子類去處理,所以下面以ImageViewAction來(lái)舉例說(shuō)明
complete
@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) {
//成功回調(diào)
callback.onSuccess();
}
}
error
@Override
public void error(Exception e) {
ImageView target = this.target.get();
if (target == null) {
return;
}
Drawable placeholder = target.getDrawable();
//如果的動(dòng)畫還在繼續(xù),那么就停止動(dòng)畫
if (placeholder instanceof AnimationDrawable) {
((AnimationDrawable) placeholder).stop();
}
//如果設(shè)置加載失敗的占位圖
if (errorResId != 0) {
target.setImageResource(errorResId);
} else if (errorDrawable != null) {
target.setImageDrawable(errorDrawable);
}
if (callback != null) {
//失敗的回調(diào)
callback.onError(e);
}
}
實(shí)際上complete跟error的并沒(méi)有做什么,都只是做了簡(jiǎn)單的回調(diào),那么也就是說(shuō)Action只是一個(gè)包裝類,沒(méi)有額外的功能
BitmapHunter
Bitmap捕捉者,或者說(shuō)是Bitmap獵人,就是用來(lái)尋找Bitmap的一個(gè)類,繼承自Runnable,說(shuō)明可以用來(lái)進(jìn)行耗時(shí)操作。
注釋
Global lock for bitmap decoding to ensure that we are only are decoding one at a time. Since this will only ever happen in background threads we help avoid excessive memory thrashing as well as potential OOMs. Shamelessly stolen from Volley.
解碼Bitmap的全局鎖用以保證我們每次只能夠解碼一個(gè)Bitmap。因?yàn)榻獯a操作只是發(fā)生在后臺(tái)線程,所以為了避免解碼時(shí)太多的內(nèi)存占用導(dǎo)致OOM,借鑒于Volley。
成員變量
final Picasso picasso;
final Dispatcher dispatcher;
final Cache cache;
final Stats stats;
final String key;
final Request data;
final int memoryPolicy;
int networkPolicy;
final RequestHandler requestHandler;
Action action;
List<Action> actions;
Bitmap result;
Future<?> future;
Picasso.LoadedFrom loadedFrom;
Exception exception;
int exifOrientation; // Determined during decoding of original resource.
int retryCount;
Picasso.Priority priority;
持有所有核心類
構(gòu)造方法
BitmapHunter(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats, Action action,RequestHandler requestHandler) {
this.sequence = SEQUENCE_GENERATOR.incrementAndGet();
this.picasso = picasso;
this.dispatcher = dispatcher;
this.cache = cache;
this.stats = stats;
this.action = action;
this.key = action.getKey();
this.data = action.getRequest();
this.priority = action.getPriority();
this.memoryPolicy = action.getMemoryPolicy();
this.networkPolicy = action.getNetworkPolicy();
this.requestHandler = requestHandler;
this.retryCount = requestHandler.getRetryCount();
}
可以看到,很多參數(shù)都是傳遞過(guò)來(lái)的,也就是自己不持有。
run
@Override
public void run() {
try {
updateThreadName(data);
//獲取Bitmap
result = hunt();
if (result == null) {
dispatcher.dispatchFailed(this);
} else {
dispatcher.dispatchComplete(this);
}
}
}
hunt
Bitmap hunt() throws IOException {
Bitmap bitmap = null;
if (shouldReadFromMemoryCache(memoryPolicy)) {
//再次讀取內(nèi)存緩存,因?yàn)椴煌恼?qǐng)求優(yōu)先級(jí)不一樣,很可能等到真正執(zhí)行的時(shí)候
//當(dāng)前的url已經(jīng)被緩存了
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;
}
}
networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy;
//如果沒(méi)有讀取緩存或者緩存讀取失敗,就開(kāi)始真正的請(qǐng)求
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 {
source.close();
} catch (IOException ignored) {
}
}
}
}
if (bitmap != null) {
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_DECODED, data.logId());
}
stats.dispatchBitmapDecoded(bitmap);
//看看是否需要進(jìn)行變換前預(yù)處理,有的話就處理
if (data.needsTransformation() || exifOrientation != 0) {
synchronized (DECODE_LOCK) {
//通過(guò)上鎖,每次只有一個(gè)進(jìn)行Decodeing
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 (bitmap != null) {
stats.dispatchBitmapTransformed(bitmap);
}
}
}
return bitmap;
}
forRequest
static BitmapHunter forRequest(
Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats, Action action) {
Request request = action.getRequest();
List<RequestHandler> requestHandlers = picasso.getRequestHandlers();
//遍歷已有的requestHandlers,看看能不能有能夠處理的requestHandler
for (int i = 0, count = requestHandlers.size(); i < count; i++) {
RequestHandler requestHandler = requestHandlers.get(i);
if (requestHandler.canHandleRequest(request)) {
return new BitmapHunter(picasso, dispatcher, cache, stats, action, requestHandler);
}
}
如果沒(méi)有的話,重新創(chuàng)建一個(gè)
return new BitmapHunter(picasso, dispatcher, cache, stats, action, ERRORING_HANDLER);
}
performSubmit
void performSubmit(Action action, boolean dismissFailed) {
//如果之前是pause過(guò),那么調(diào)用resume
if (pausedTags.contains(action.getTag())) {
pausedActions.put(action.getTarget(), action);
return;
}
//通過(guò)Key獲取BitmapHunter
BitmapHunter hunter = hunterMap.get(action.getKey());
if (hunter != null) {
//將action添加進(jìn)BitmapHunter
hunter.attach(action);
return;
}
if (service.isShutdown()) {
//如果線程池關(guān)閉,直接返回
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
}
return;
}
//創(chuàng)建一個(gè)BitmapHunter
hunter = forRequest(action.getPicasso(), this, cache, stats, action);
//拿到線程池執(zhí)行的結(jié)果,BitmapHunter肯定是個(gè)Runnable或者Future
hunter.future = service.submit(hunter);
//存入map中
hunterMap.put(action.getKey(), hunter);
if (dismissFailed) {
failedActions.remove(action.getTarget());
}
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
}
}
performPauseTag
void performPauseTag(Object tag) {
// 已經(jīng)paused過(guò),直接返回
if (!pausedTags.add(tag)) {
return;
}
// Go through all active hunters and detach/pause the requests
// that have the paused tag.
for (Iterator<BitmapHunter> it = hunterMap.values().iterator(); it.hasNext(); ) {
BitmapHunter hunter = it.next();
boolean loggingEnabled = hunter.getPicasso().loggingEnabled;
Action single = hunter.getAction();
List<Action> joined = hunter.getActions();
boolean hasMultiple = joined != null && !joined.isEmpty();
// Hunter has no requests, bail early.
if (single == null && !hasMultiple) {
continue;
}
//判斷當(dāng)前唯一的Action是否跟暫停的tag相同
if (single != null && single.getTag().equals(tag)) {
//從hunter中移除
hunter.detach(single);
//添加進(jìn)pausedActions
pausedActions.put(single.getTarget(), single);
}
if (hasMultiple) {
//如果有多個(gè)Action
for (int i = joined.size() - 1; i >= 0; i--) {
Action action = joined.get(i);
if (!action.getTag().equals(tag)) {
continue;
}
//跟單個(gè)一樣
hunter.detach(action);
pausedActions.put(action.getTarget(), action);
}
}
}
}
performResumeTag
void performResumeTag(Object tag) {
// 移除恢復(fù)的tag
if (!pausedTags.remove(tag)) {
return;
}
List<Action> batch = null;
for (Iterator<Action> i = pausedActions.values().iterator(); i.hasNext(); ) {
Action action = i.next();
if (action.getTag().equals(tag)) {
if (batch == null) {
batch = new ArrayList<>();
}
//添加進(jìn)List集合匯總
batch.add(action);
//從暫停的集合中移除
i.remove();
}
}
if (batch != null) {
//切換到主線程,執(zhí)行resumeAction
mainThreadHandler.sendMessage(
mainThreadHandler.obtainMessage(REQUEST_BATCH_RESUME, batch));
}
}
實(shí)際上performResumeTag在Picasso的分析中已經(jīng)說(shuō)明,如果沒(méi)有設(shè)置內(nèi)存緩存,那么相當(dāng)于重新開(kāi)啟一個(gè)請(qǐng)求,如果設(shè)置了內(nèi)存緩存,讀取失敗也會(huì)重新開(kāi)啟一個(gè)請(qǐng)求,只有在開(kāi)啟內(nèi)存緩存并且讀取成功performResumeTag才不會(huì)重新創(chuàng)建請(qǐng)求。
decodeStream
static Bitmap decodeStream(Source source, Request request) throws IOException {
BufferedSource bufferedSource = Okio.buffer(source);
boolean isWebPFile = Utils.isWebPFile(bufferedSource);
boolean isPurgeable = request.purgeable && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP;
BitmapFactory.Options options = RequestHandler.createBitmapOptions(request);
boolean calculateSize = RequestHandler.requiresInSampleSize(options);
if (isWebPFile || isPurgeable) {
byte[] bytes = bufferedSource.readByteArray();
if (calculateSize) {
BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
RequestHandler.calculateInSampleSize(
request.targetWidth, request.targetHeight, options,request);
}
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
} else {
InputStream stream = bufferedSource.inputStream();
if (calculateSize) {
// TODO use an InputStream that buffers with Okio...
MarkableInputStream markStream = new MarkableInputStream(stream);
stream = markStream;
markStream.allowMarksToExpire(false);
long mark = markStream.savePosition(1024);
BitmapFactory.decodeStream(stream, null, options);
//計(jì)算Bitmap的尺寸
RequestHandler.calculateInSampleSize(
request.targetWidth, request.targetHeight, options,request);
markStream.reset(mark);
markStream.allowMarksToExpire(true);
}
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);
if (bitmap == null) {
throw new IOException("Failed to decode stream.");
}
return bitmap;
}
}
calculateInSampleSize(RequestHandler的方法)
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);
}
}
options.inSampleSize = sampleSize;
options.inJustDecodeBounds = false;
}
通過(guò)傳入目標(biāo)寬高以及實(shí)際的寬高進(jìn)行縮放,然后進(jìn)行縮放得到想要的尺寸
Dispatcher
成員變量
final DispatcherThread dispatcherThread;//HandlerThread,用于在子線程中創(chuàng)建Looper
final Context context;
final ExecutorService service;//線程池
final Downloader downloader;//圖片下載器
final Map<String, BitmapHunter> hunterMap;//存放BitmapHunter
final Map<Object, Action> failedActions;//失敗的請(qǐng)求
final Map<Object, Action> pausedActions;//暫停的請(qǐng)求
final Set<Object> pausedTags;//暫停的tag集合
final Handler handler;//Dispatcher中消息轉(zhuǎn)發(fā)的Handler
final Handler mainThreadHandler;//主線程中的Handler
final Cache cache;
final Stats stats;
final List<BitmapHunter> batch;//BitmapHunter集合
final NetworkBroadcastReceiver receiver;//網(wǎng)絡(luò)狀態(tài)監(jiān)聽(tīng)的廣播
final boolean scansNetworkChanges;網(wǎng)絡(luò)狀態(tài)是否切換的標(biāo)志
構(gòu)造方法
Dispatcher(Context context, ExecutorService service, Handler mainThreadHandler,
Downloader downloader, Cache cache, Stats stats) {
this.dispatcherThread = new DispatcherThread();
this.dispatcherThread.start();//啟動(dòng)HandlerThread
Utils.flushStackLocalLeaks(dispatcherThread.getLooper());
this.context = context;
this.service = service;
this.hunterMap = new LinkedHashMap<>();
this.failedActions = new WeakHashMap<>();//軟引用
this.pausedActions = new WeakHashMap<>();//軟引用
this.pausedTags = new HashSet<>();
this.handler = new DispatcherHandler(dispatcherThread.getLooper(), this);
this.downloader = downloader;
this.mainThreadHandler = mainThreadHandler;
this.cache = cache;
this.stats = stats;
this.batch = new ArrayList<>(4);
this.airplaneMode = Utils.isAirplaneModeOn(this.context);
//如果沒(méi)有獲取到網(wǎng)絡(luò)狀態(tài)改變的權(quán)限則全部為false
this.scansNetworkChanges =hasPermission(context,Manifest.permission.ACCESS_NETWORK_STATE);
//創(chuàng)建網(wǎng)絡(luò)狀態(tài)監(jiān)聽(tīng)的廣播
this.receiver = new NetworkBroadcastReceiver(this);
//注冊(cè)廣播
receiver.register();
}
Handler
這是區(qū)別于MainHandler的一個(gè)內(nèi)部的Handler,用在這里可以讓邏輯更加清晰,實(shí)際上不用也可以。
private static class DispatcherHandler extends Handler {
private final Dispatcher dispatcher;
//傳入子線程的Looper
DispatcherHandler(Looper looper, Dispatcher dispatcher) {
super(looper);
this.dispatcher = dispatcher;
}
@Override
public void handleMessage(final Message msg) {
switch (msg.what) {
case REQUEST_SUBMIT: {//提交請(qǐng)求
Action action = (Action) msg.obj;
dispatcher.performSubmit(action);
break;
}
case REQUEST_CANCEL: {//取消請(qǐng)求
Action action = (Action) msg.obj;
dispatcher.performCancel(action);
break;
}
case TAG_PAUSE: {//暫停請(qǐng)求
Object tag = msg.obj;
dispatcher.performPauseTag(tag);
break;
}
case TAG_RESUME: {//恢復(fù)請(qǐng)求
Object tag = msg.obj;
dispatcher.performResumeTag(tag);
break;
}
case HUNTER_COMPLETE: {//請(qǐng)求完成
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performComplete(hunter);
break;
}
case HUNTER_RETRY: {//請(qǐng)求重試
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performRetry(hunter);
break;
}
}
}
NetworkBroadcastReceiver
網(wǎng)絡(luò)監(jiān)聽(tīng)的廣播
static class NetworkBroadcastReceiver extends BroadcastReceiver {
static final String EXTRA_AIRPLANE_STATE = "state";
private final Dispatcher dispatcher;
NetworkBroadcastReceiver(Dispatcher dispatcher) {
this.dispatcher = dispatcher;
}
void register() {
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_AIRPLANE_MODE_CHANGED);
if (dispatcher.scansNetworkChanges) {
filter.addAction(CONNECTIVITY_ACTION);
}
dispatcher.context.registerReceiver(this, filter);
}
void unregister() {
dispatcher.context.unregisterReceiver(this);
}
@SuppressLint("MissingPermission")
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
return;
}
final String action = intent.getAction();
if (ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
if (!intent.hasExtra(EXTRA_AIRPLANE_STATE)) {
return; /
}
dispatcher.dispatchAirplaneModeChange(
intent.getBooleanExtra(EXTRA_AIRPLANE_STATE, false));
} else if (CONNECTIVITY_ACTION.equals(action)) {
ConnectivityManager connectivityManager = getService(context, CONNECTIVITY_SERVICE);
//將網(wǎng)絡(luò)狀態(tài)的變化通知內(nèi)部的Handler
dispatcher.dispatchNetworkStateChange(connectivityManager.getActiveNetworkInfo());
}
}
}
dispatchNetworkStateChange最后還是調(diào)用了adjustThreadCount
void adjustThreadCount(NetworkInfo info) {
if (info == null || !info.isConnectedOrConnecting()) {
setThreadCount(DEFAULT_THREAD_COUNT);
return;
}
switch (info.getType()) {
case ConnectivityManager.TYPE_WIFI:
case ConnectivityManager.TYPE_WIMAX:
case ConnectivityManager.TYPE_ETHERNET:
setThreadCount(4);
break;
case ConnectivityManager.TYPE_MOBILE:
switch (info.getSubtype()) {
case TelephonyManager.NETWORK_TYPE_LTE: // 4G
case TelephonyManager.NETWORK_TYPE_HSPAP:
case TelephonyManager.NETWORK_TYPE_EHRPD:
setThreadCount(3);
break;
case TelephonyManager.NETWORK_TYPE_UMTS: // 3G
case TelephonyManager.NETWORK_TYPE_CDMA:
case TelephonyManager.NETWORK_TYPE_EVDO_0:
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
setThreadCount(2);
break;
case TelephonyManager.NETWORK_TYPE_GPRS: // 2G
case TelephonyManager.NETWORK_TYPE_EDGE:
setThreadCount(1);
break;
default:
setThreadCount(DEFAULT_THREAD_COUNT);
}
break;
default:
setThreadCount(DEFAULT_THREAD_COUNT);
}
}
也就是根據(jù)不同的網(wǎng)絡(luò)狀態(tài)設(shè)置線程池的核心線程數(shù)以及最大線程數(shù)
performSubmit
void performSubmit(Action action, boolean dismissFailed) {
//如果之前是pause過(guò),那么調(diào)用resume
if (pausedTags.contains(action.getTag())) {
pausedActions.put(action.getTarget(), action);
return;
}
//通過(guò)Key獲取BitmapHunter
BitmapHunter hunter = hunterMap.get(action.getKey());
if (hunter != null) {
//將action添加進(jìn)BitmapHunter
hunter.attach(action);
return;
}
if (service.isShutdown()) {
//如果線程池關(guān)閉,直接返回
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
}
return;
}
//創(chuàng)建一個(gè)BitmapHunter
hunter = forRequest(action.getPicasso(), this, cache, stats, action);
//拿到線程池執(zhí)行的結(jié)果,BitmapHunter肯定是個(gè)Runnable或者Future
hunter.future = service.submit(hunter);
//存入map中
hunterMap.put(action.getKey(), hunter);
if (dismissFailed) {
failedActions.remove(action.getTarget());
}
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
}
}
performCancel
void performCancel(Action action) {
String key = action.getKey();
//獲取hunter
BitmapHunter hunter = hunterMap.get(key);
if (hunter != null) {
從hunter中移除這個(gè)Action
hunter.detach(action);
if (hunter.cancel()) {
hunterMap.remove(key);
}
}
//如果pausedTags中含有此Action,移除掉
if (pausedTags.contains(action.getTag())) {
pausedActions.remove(action.getTarget());
}
//嘗試著從失敗的Action中移除此Action
Action remove = failedActions.remove(action.getTarget());
}
shutdown
void shutdown() {
// 關(guān)閉線程池
if (service instanceof PicassoExecutorService) {
service.shutdown();
}
//關(guān)閉下載器
downloader.shutdown();
//退出handler
dispatcherThread.quit();
//移除廣播
Picasso.HANDLER.post(new Runnable() {
@Override
public void run() {
receiver.unregister();
}
});
}
總結(jié)
上面分析了Picasso的核心類,還有一些比較重要的類,Lrucache,PicassoExecutorService,由于Lrucache跟Volley的DiskBaseCache并無(wú)區(qū)別,底層采用LinkedHashMap,通過(guò)使用的順序來(lái)進(jìn)行排序,容量不足時(shí)刪除最近最少使用的數(shù)據(jù),而PicassoExecutorService屬于線程池,之前也分析過(guò)。
Picasso相對(duì)于Volley注釋太少,不是很好閱讀,所幸命名比較規(guī)范,可以根據(jù)名字大致猜出這個(gè)類是干什么的,整體封裝性比Volley好,但是擴(kuò)展性不如Volley,不過(guò)都有很多值得學(xué)習(xí)的地方,下面簡(jiǎn)單對(duì)比分析一下:
| Volley | Picasso | |
|---|---|---|
| Request | Request | RequestCreator—>Request—>Action—>BitmapHunter |
| Cache | DiskLruCache | DiskLruCache&DiskDiskLruCache |
| RequstQueue | BlockingQueue | ThreadPoolExecutor |
| Dispatcher | CacheDispatcher& NetworkDispatcher | DispatcherThread |
| TaskAction | cancel | cancel,pause,resume |