Picasso代碼初探
簡(jiǎn)介
Picasso是square開(kāi)源的一個(gè)Android網(wǎng)絡(luò)圖片處理的庫(kù),鑒于使用過(guò)okHttp、Retrofit等square的NB庫(kù),因此打算嘗試下Picasso,了解下Picasso的NB之處。
使用
Picasso使用的語(yǔ)法與Glide一樣,或者說(shuō)Glide與Picasso一樣...
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
代碼的解讀也主要基于上面這行代碼。
代碼查看
with方法
通過(guò)上述代碼可以看出Picasso加載圖片的代碼使用構(gòu)造器模式,通過(guò)鏈?zhǔn)絺鬟fPicasso單例。首先查看Picasso類中的with方法:
public static Picasso with(Context context) {
if (singleton == null) {
synchronized (Picasso.class) {
if (singleton == null) {
singleton = new Builder(context).build();
}
}
}
return singleton;
}
with方法為Picasso類的靜態(tài)方法,通過(guò)構(gòu)造器返回Picasso的全局單例。
public Picasso build() {
Context context = this.context;
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);
}
通過(guò)build方法代碼可以看出,Picasso實(shí)例包含許多內(nèi)容,下載器、緩存、服務(wù)、請(qǐng)求發(fā)送等。下面一步一步的來(lái)看這幾個(gè)實(shí)體:
- downloader
- cache
- service
- transformer
downloader
通過(guò)反射判斷使用OkHttpLoaderCreator或者UrlConnectionDownloader,通過(guò)OkHttpLoaderCreator建立的downloader還會(huì)通過(guò)getCacheDir方法獲取緩存路徑建立文件名為“picasso-cache”的Picasso的緩存文件。其中OkHttpDownloader為通過(guò)OkHttp請(qǐng)求來(lái)下載網(wǎng)絡(luò)圖片的類,具體內(nèi)容體現(xiàn)在后面講述的load方法中。
cache
緩存默認(rèn)使用LRU算法,即least-recently used,近期最少使用算法。首先在LruCache的構(gòu)造函數(shù)中計(jì)算出一個(gè)合理的大小,作為緩存的最大空間。
static int calculateMemoryCacheSize(Context context) {
ActivityManager am = getService(context, ACTIVITY_SERVICE);
boolean largeHeap = (context.getApplicationInfo().flags & FLAG_LARGE_HEAP) != 0;
int memoryClass = am.getMemoryClass();
if (largeHeap && SDK_INT >= HONEYCOMB) {
memoryClass = ActivityManagerHoneycomb.getLargeMemoryClass(am);
}
// Target ~15% of the available heap.
return 1024 * 1024 * memoryClass / 7;
}
使用可用內(nèi)存堆的1/7作為圖片緩存(不清楚這個(gè)大小有啥依據(jù)沒(méi)有,本以為應(yīng)該給更多空間)。關(guān)于具體內(nèi)存大小,與Android系統(tǒng)配置相關(guān),我參考的是這篇博客。
service
PicassoExecutorService實(shí)現(xiàn)Picasso線程池,構(gòu)造函數(shù)中實(shí)例化工作隊(duì)列和線程工廠。
transformer
RequestTransformer,請(qǐng)求在被執(zhí)行前經(jīng)過(guò)一層轉(zhuǎn)換。
stat
通過(guò)Stat標(biāo)記緩存的狀態(tài)(命中數(shù)、未命中數(shù)、總大小、平均大小、下載次數(shù)等)
dispatcher
分發(fā)處理事件,如圖片加載完成、請(qǐng)求提交、請(qǐng)求取消等。
load方法
通過(guò)傳遞的String返回RequestCreator,代碼如下:
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);
}
Request同樣使用Builder模式進(jìn)行構(gòu)建,設(shè)置基本參數(shù)。
into方法
public void into(Target target) {
long started = System.nanoTime();
checkMain();
if (target == null) {
throw new IllegalArgumentException("Target must not be null.");
}
if (deferred) {
throw new IllegalStateException("Fit cannot be used with a Target.");
}
if (!data.hasImage()) {
picasso.cancelRequest(target);
target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null);
return;
}
Request request = createRequest(started);
String requestKey = createKey(request);
if (shouldReadFromMemoryCache(memoryPolicy)) {
Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
if (bitmap != null) {
picasso.cancelRequest(target);
target.onBitmapLoaded(bitmap, MEMORY);
return;
}
}
target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null);
Action action =
new TargetAction(picasso, target, request, memoryPolicy, networkPolicy, errorDrawable,
requestKey, tag, errorResId);
picasso.enqueueAndSubmit(action);
}
into方法首先進(jìn)行一系列的校驗(yàn),如是否是在主(UI)線程,目標(biāo)ImageView是否為空,URI或ResourceId是否為空等。經(jīng)過(guò)校驗(yàn)后,建立請(qǐng)求,并通過(guò)請(qǐng)求生成一個(gè)requestKey,該Key即為緩存中緩存該圖片的Key值,請(qǐng)求網(wǎng)絡(luò)前先通過(guò)該Key檢查圖片是否在緩存中。否則將請(qǐng)求加入Picasso的請(qǐng)求隊(duì)列中。
核心類為Dispatcher,通過(guò)DispatcherThread和BitmapHunter進(jìn)行整個(gè)工作隊(duì)列和Bitmap緩存等的管理。
Android開(kāi)發(fā)新手,若有錯(cuò)誤請(qǐng)指出,謝謝~