Picasso代碼初探
簡介
Picasso是square開源的一個Android網絡圖片處理的庫,鑒于使用過okHttp、Retrofit等square的NB庫,因此打算嘗試下Picasso,了解下Picasso的NB之處。
使用
Picasso使用的語法與Glide一樣,或者說Glide與Picasso一樣...
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
代碼的解讀也主要基于上面這行代碼。
代碼查看
with方法
通過上述代碼可以看出Picasso加載圖片的代碼使用構造器模式,通過鏈式傳遞Picasso單例。首先查看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類的靜態方法,通過構造器返回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);
}
通過build方法代碼可以看出,Picasso實例包含許多內容,下載器、緩存、服務、請求發送等。下面一步一步的來看這幾個實體:
- downloader
- cache
- service
- transformer
downloader
通過反射判斷使用OkHttpLoaderCreator或者UrlConnectionDownloader,通過OkHttpLoaderCreator建立的downloader還會通過getCacheDir方法獲取緩存路徑建立文件名為“picasso-cache”的Picasso的緩存文件。其中OkHttpDownloader為通過OkHttp請求來下載網絡圖片的類,具體內容體現在后面講述的load方法中。
cache
緩存默認使用LRU算法,即least-recently used,近期最少使用算法。首先在LruCache的構造函數中計算出一個合理的大小,作為緩存的最大空間。
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;
}
使用可用內存堆的1/7作為圖片緩存(不清楚這個大小有啥依據沒有,本以為應該給更多空間)。關于具體內存大小,與Android系統配置相關,我參考的是這篇博客。
service
PicassoExecutorService實現Picasso線程池,構造函數中實例化工作隊列和線程工廠。
transformer
RequestTransformer,請求在被執行前經過一層轉換。
stat
通過Stat標記緩存的狀態(命中數、未命中數、總大小、平均大小、下載次數等)
dispatcher
分發處理事件,如圖片加載完成、請求提交、請求取消等。
load方法
通過傳遞的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模式進行構建,設置基本參數。
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方法首先進行一系列的校驗,如是否是在主(UI)線程,目標ImageView是否為空,URI或ResourceId是否為空等。經過校驗后,建立請求,并通過請求生成一個requestKey,該Key即為緩存中緩存該圖片的Key值,請求網絡前先通過該Key檢查圖片是否在緩存中。否則將請求加入Picasso的請求隊列中。
核心類為Dispatcher,通過DispatcherThread和BitmapHunter進行整個工作隊列和Bitmap緩存等的管理。
Android開發新手,若有錯誤請指出,謝謝~