Picasso的構(gòu)建過程如下:
if (downloader == null) {
downloader = Utils.createDefaultDownloader(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);
Downloader
Picasso需要的默認(rèn)下載器。
try {
Class.forName("com.squareup.okhttp.OkHttpClient");
return OkHttpLoaderCreator.create(context);
} catch (ClassNotFoundException ignored) {
}
return new UrlConnectionDownloader(context);
該下載器會(huì)首先查找是否有okHttpClient類,如果找到,則創(chuàng)建并進(jìn)行配置。OkHttpClient 的緩存在Disk上,緩存大小為整個(gè)磁盤空間的2%(通過statFs計(jì)算得到),緩存路徑在/data/data/packageName/cache/picasso-cache下。
如果沒有找到OkHttpClienet,則使用HttpURLConnection完成下載工作。在Android4.0以上(包括4.0),提供了HttpResponseCache來(lái)支持硬盤緩存的功能。緩存空間和緩存路徑不變。
如果有在項(xiàng)目中使用OkHttp,可以將自定義的OkHttpClient單例配置進(jìn)Downloader中(繼承Downloader,在它的load函數(shù)中使用定義好的okHttpClient),這樣將保證所有網(wǎng)絡(luò)請(qǐng)求使用同一套client。
LruCache
基于LRU(近期最少使用)算法的內(nèi)存緩存器。
默認(rèn)緩存大小為app內(nèi)存的1/7,大約15%。
內(nèi)部本質(zhì)上維持著一個(gè)LinkedHashMap來(lái)存儲(chǔ)Btimap,主要是針對(duì)Bitmap的set和get。
set的時(shí)候,會(huì)統(tǒng)計(jì)Bitmap的大小,從而更新緩存中Bitmap總的大小,在set工作的最后,判斷當(dāng)前Bitmap的總量是否超過設(shè)定的緩存大小,從而決定是否需要對(duì)緩存進(jìn)行清理。
如果需要進(jìn)行清理,選擇LinkedHashMap的優(yōu)勢(shì)就出現(xiàn)了,不斷從迭代器中按照存入的先后順序取出Bitmap進(jìn)行remove。
get的時(shí)候,即是從Map中取,在這個(gè)過程會(huì)統(tǒng)計(jì)擊中數(shù)(hitCount)和未擊中數(shù)(missCount)。
如果你想統(tǒng)計(jì)擊中率,可以主動(dòng)創(chuàng)建一個(gè)LruCache對(duì)象,在Picasso構(gòu)建的時(shí)候添加進(jìn)去,這時(shí),可以取出hitCount和missCount?;蛘咝枰玫疆?dāng)前緩存大小,或者需要清空緩存,同樣需要這樣做。
PicassoExecutorService
查找Bitmap的線程池。
阻塞隊(duì)列使用PriorityBlockingQueue,同時(shí)根據(jù)網(wǎng)絡(luò)情況,會(huì)對(duì)線程池中的線程數(shù)進(jìn)行調(diào)整。如果無(wú)法感知到網(wǎng)絡(luò)情況,默認(rèn)線程數(shù)為3,有wifi情況為4,4g情況為3,3g情況為2,2g情況為1。
在該線程池中,執(zhí)行的實(shí)際上是通過BitmapHunter獲取Bitmap并對(duì)Bitmap進(jìn)行轉(zhuǎn)換的過程。
在BitmapHunter中核心代碼如下:
RequestHandler.Result result = requestHandler.load(data, networkPolicy);
bitmap = result.getBitmap();
上述的requestHandler是在Picasso實(shí)例化的時(shí)候在構(gòu)造函數(shù)中添加進(jìn)去的。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));
我們可以看到,對(duì)于需要網(wǎng)絡(luò)請(qǐng)求的得到Bitmap的過程是由NetworkRequestHandler來(lái)處理的。它會(huì)檢測(cè)該bitmap是否在磁盤上,還是需要進(jìn)行網(wǎng)絡(luò)訪問(本質(zhì)上,它把這件事交給了okHttpClient來(lái)處理)。
在BitmapHunter中獲取Bitmap之后,如果需要會(huì)對(duì)該Bitmap進(jìn)行轉(zhuǎn)換然后返回。
RequestTransformer
在request被提交之前使用該transformer來(lái)對(duì)request進(jìn)行修改。這是一個(gè)測(cè)試版特性,后續(xù)版本中可能不會(huì)兼容該特性。
Dispatcher
Dispatcher的主要作用,是處理各種動(dòng)作。
case REQUEST_SUBMIT: {
Action action = (Action) msg.obj;
dispatcher.performSubmit(action);
break;
}
case REQUEST_CANCEL: {
Action action = (Action) msg.obj;
dispatcher.performCancel(action);
break;
}
case TAG_PAUSE: {
Object tag = msg.obj;
dispatcher.performPauseTag(tag);
break;
}
case TAG_RESUME: {
Object tag = msg.obj;
dispatcher.performResumeTag(tag);
break;
}
case HUNTER_COMPLETE: {
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performComplete(hunter);
break;
}
case HUNTER_RETRY: {
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performRetry(hunter);
break;
}
case HUNTER_DECODE_FAILED: {
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performError(hunter, false);
break;
}
case HUNTER_DELAY_NEXT_BATCH: {
dispatcher.performBatchComplete();
break;
}
case NETWORK_STATE_CHANGE: {
NetworkInfo info = (NetworkInfo) msg.obj;
dispatcher.performNetworkStateChange(info);
break;
}
case AIRPLANE_MODE_CHANGE: {
dispatcher.performAirplaneModeChange(msg.arg1 == AIRPLANE_MODE_ON);
break;
}
default:
Picasso.HANDLER.post(new Runnable() {
@Override public void run() {
throw new AssertionError("Unknown handler message received: " + msg.what);
}
});
加載到ImageView過程
picasso.load(imageUrl).into(view);
load方法將返回一個(gè)RequestCreator對(duì)象。
在into的過程中,會(huì)為每個(gè)bitmap產(chǎn)生一個(gè)唯一的key,通過這個(gè)key來(lái)檢查該bitmap是或在內(nèi)存(LruCache)中,如果存在則直接返回(對(duì)磁盤緩存的檢查,是在BitmapHunte中進(jìn)行的,實(shí)際上由okHttpClient完成)。否則產(chǎn)生一個(gè)ImageViewAction提交給Dispatcher處理。
在Dispatcher中,核心代碼為:
//如果action被設(shè)置為pause tag
if (pausedTags.contains(action.getTag())) {
......
return;
}
//如果action不是新的
BitmapHunter hunter = hunterMap.get(action.getKey());
if (hunter != null) {
hunter.attach(action);
return;
}
//如果線程池被關(guān)閉了
if (service.isShutdown()) {
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
}
return;
}
//生成BitmapHunter
hunter = forRequest(action.getPicasso(), this, cache, stats, action);
//交給線程池,執(zhí)行
hunter.future = service.submit(hunter);
hunterMap.put(action.getKey(), hunter);
......