圖片加載框架Picasso源碼的簡(jiǎn)單分析(一)
本篇文章只是對(duì)Picasso加載流程做加單的分析,相對(duì)于其他常用的圖片框架Picasso算是比較精煉簡(jiǎn)潔。 但是即便再簡(jiǎn)單的圖片加載框架都會(huì)包含數(shù)據(jù)流讀取、內(nèi)存策略、尺寸剪裁等模塊, 一次性通篇分析完整個(gè)框架源碼內(nèi)容信息過多,不利于讀者快速閱讀和消化吸收。所以本篇就簡(jiǎn)單的說明。相關(guān)知識(shí)點(diǎn)會(huì)在其他相關(guān)博客中說明。
1. Picasso的總體流程:
Picasso使用采用鏈?zhǔn)降姆绞?,圖片的加載流程如下:
1)創(chuàng)建Picassco和RequestCreator對(duì)象, RequestCreator封裝了加載資源文件的來源。
2)RequestCreator將請(qǐng)求封裝為Request對(duì)象,然后創(chuàng)建Action對(duì)象(例如ImageViewAction)。
3)Picasso對(duì)象將action分發(fā)給Dispatcher對(duì)象,Dispatcher創(chuàng)建BitmapHunter, 同時(shí)將Action封裝到BitmapHunter,BitmapHunter是Runnable任務(wù)類。然后將BitmapHunter提交到線程池去執(zhí)行。
4)BitmapHunter調(diào)用RequestHandler來處理當(dāng)前request, 獲取數(shù)據(jù)流InputStream封裝到Result對(duì)象中。BitmapHunter通過Result獲取InputStream讀取解析出Bitmap對(duì)象。
5)BitmapHunter調(diào)用Dispatcher將自身回調(diào)到Picasso.complete()方法中,獲取Action對(duì)象。Action將生成的bitmap設(shè)置到ImageView中。
代碼時(shí)序圖如下:

2. 相關(guān)類的作用和創(chuàng)建過程以圖片獲取過程
2.1 Picasso對(duì)象的創(chuàng)建過程
Picasso創(chuàng)建采用Builder建造者模式創(chuàng)建單例, 代碼如下:
public static Picasso with(Context context) {
if (singleton == null) {
synchronized (Picasso.class) {
if (singleton == null) {
singleton = new Builder(context).build();
}
}
}
return singleton;
}
Builder模式的優(yōu)點(diǎn)在于開發(fā)者可以通過配置組件的方法來創(chuàng)建對(duì)象實(shí)例,Picasso.Builder類的定義如下:
public static class Builder {
private final Context context; // APP全局上下文Contxt
private Downloader downloader; //自定義現(xiàn)下載管理類
private ExecutorService service; //線程池
private Cache cache; //自定義緩存
private Listener listener;
private RequestTransformer transformer; //圖片尺寸裁剪類
private List<RequestHandler> requestHandlers;//圖片實(shí)際下載處理類
private Bitmap.Config defaultBitmapConfig;
Builder的build方法利用上面的默認(rèn)配置類定義和創(chuàng)建Picasso對(duì)象實(shí)例, 代碼如下:
public Picasso build() {
。。。。。。。。
if (downloader == null) {
//創(chuàng)建默認(rèn)下載管理器
downloader = Utils.createDefaultDownloader(context);
}
if (cache == null) {
//創(chuàng)建默認(rèn)緩存
cache = new LruCache(context);
}
if (service == null) {
//創(chuàng)建默認(rèn)線程池
service = new PicassoExecutorService();
}
if (transformer == null) {
//創(chuàng)建默認(rèn)轉(zhuǎn)化器
transformer = RequestTransformer.IDENTITY;
}
//創(chuàng)建請(qǐng)求分發(fā)調(diào)度管理器
Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);
//根據(jù)前面創(chuàng)建的各種默認(rèn)組件封裝Picasso對(duì)象
return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,
defaultBitmapConfig, indicatorsEnabled, loggingEnabled);
}
2.2 RequestCreator
RequestCreator作用是根求請(qǐng)求的數(shù)據(jù)來源類型創(chuàng)建和封裝Requst和Action對(duì)象。Picasso對(duì)象在load()方法中創(chuàng)建RequestCreator對(duì)象。RequestCreator對(duì)象的into()方法中創(chuàng)建Requst和Action對(duì)象。
public class RequestCreator {
。。。。。。
private final Picasso picasso; //Picasso對(duì)象實(shí)例
private final Request.Builder data; //Request Builder構(gòu)造器,用于生成Request
。。。。。。
}
Picasso在load方法中直接通過new的方式生成RequestCreator對(duì)象。RequestCreator構(gòu)造方法如下:
RequestCreator(Picasso picasso, Uri uri, int resourceId) {
//Picasso實(shí)例對(duì)象
this.picasso = picasso;
//生成Request對(duì)象構(gòu)造器
this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);
}
RequestCreator對(duì)象的into()方法中生成Request和Action對(duì)象
public void into(ImageView target, Callback callback) {
//創(chuàng)建Request對(duì)象
Request request = createRequest(started);
//生成requestKey,用于索引查找
String requestKey = createKey(request);
if (shouldReadFromMemoryCache(memoryPolicy)) {
Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
if (bitmap != null) {
//如果通過所以查找到內(nèi)存中存在已經(jīng)生成的bitmap對(duì)象,直接返回,不做進(jìn)一步操作
picasso.cancelRequest(target);
setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled);
return;
}
}
//創(chuàng)建Action對(duì)象
Action action =
new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,
errorDrawable, requestKey, tag, callback, noFade);
//將Action通過Picasso對(duì)象分發(fā)給Dispathcer對(duì)象
picasso.enqueueAndSubmit(action);
}
2.3 Dispatcher
Dispatcher類的主要作用是講Action對(duì)象封裝到BitmapHunter中。同事將 BitmapHunter對(duì)象提交到線程池執(zhí)行,BitmapHunter是Runnable類型任務(wù)執(zhí)行類。performSubmit()方法用于獲取BitmapHunter對(duì)象并提交到線程池中:
void performSubmit(Action action, boolean dismissFailed) {
。。。。。。
創(chuàng)建BitmapHunter對(duì)象
hunter = forRequest(action.getPicasso(), this, cache, stats, action);
//BitmapHunter對(duì)象提交到線程池執(zhí)行
hunter.future = service.submit(hunter);
。。。。。。
}
BitmapHunter對(duì)象實(shí)際在forRequest()方法中創(chuàng)建, forRequest()從Action中獲取Request,從Picasso對(duì)象中獲取圖片源處理組件封裝到BitmapHunter中。 代碼如下:
static BitmapHunter forRequest(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats,
Action action) {
//從Action中獲取Request對(duì)象
Request request = action.getRequest();
//獲取圖片源處理組件
List<RequestHandler> requestHandlers = picasso.getRequestHandlers();
//創(chuàng)建BitmapHunter對(duì)象實(shí)例
return new BitmapHunter(picasso, dispatcher, cache, stats, action, ERRORING_HANDLER);
}
2.4 BitmapHunter
BitmapHunter類, 實(shí)際處理圖片數(shù)據(jù)請(qǐng)求和生成Bitmap的關(guān)鍵類,核心方法是hunt()防范,線程執(zhí)行入口方法通過hunt()獲取Bitmap對(duì)象,并回調(diào)給Dispathcer對(duì)象。run()方法執(zhí)行代碼如下:
public void run() {
//獲取Bitmap對(duì)象
result = hunt();
//通過Dispatcher回調(diào)成功獲取bitmap
dispatcher.dispatchComplete(this);
}
hunt()方法
Bitmap hunt() throws IOException {
。。。。。
//通過RequestHandler對(duì)象獲取文件數(shù)據(jù)流InputStream,并把InputStream封裝到Result中。
RequestHandler.Result result = requestHandler.load(data, networkPolicy);
//從Result中獲取文件數(shù)據(jù)流
InputStream is = result.getStream();
try {
//生成Bitmap對(duì)象實(shí)例
bitmap = decodeStream(is, data);
} finally {
Utils.closeQuietly(is);
}
//返回對(duì)象實(shí)例
return bitmap;
。。。。。。
}
2.5RequestHandler
RequestHandler類的作用是根據(jù)不同類型的圖片數(shù)據(jù)來源(網(wǎng)絡(luò)、文件、資源文件等)獲取想對(duì)應(yīng)的InputStram,封裝到Result中。以AssetRequestHandler為例,執(zhí)行代碼如下:
public Result load(Request request, int networkPolicy) throws IOException {
//獲取Asset中資源文件的文件流InputStream
InputStream is = assetManager.open(getFilePath(request));
//將圖片文件流InputStream封裝到Result中,并返回。
return new Result(is, DISK);
}
3. Bitmap獲取后回調(diào)和加載過程
上面2.4 BitmapHunter節(jié)中介紹到Bitmap圖像獲取后會(huì)通過Dispatcher對(duì)象實(shí)例回調(diào),最終會(huì)回調(diào)到Picasso方法complete()中。代碼如下:
void complete(BitmapHunter hunter) {
//獲取Action對(duì)象
Action single = hunter.getAction();
//獲取Bitmap對(duì)象
Bitmap result = hunter.getResult();
if (single != null) {
//將Bitmap對(duì)象交給Action對(duì)象處理
deliverAction(result, from, single);
}
}
3.1 Action
Action類的作用是圖片Bitmap對(duì)象獲取成功后,將Bitmap對(duì)象設(shè)置到ImageView中。其核心方法是complete()房,代碼如下:
public void complete(Bitmap result, Picasso.LoadedFrom from) {
。。。。。。
//從Action中獲取ImageView對(duì)象
ImageView target = this.target.get();
//獲取上下文實(shí)例
Context context = picasso.context;
//通過PicassoDrawable將Bitmap設(shè)置到ImageView中
PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);
if (callback != null) {
//圖片加載成功回調(diào)
callback.onSuccess();
}
。。。。。。
}
本片文章根據(jù)時(shí)序流程介紹了Picasso圖片數(shù)據(jù)請(qǐng)求過程和加載過程,由于篇幅原因具體實(shí)現(xiàn)細(xì)節(jié)無法仔細(xì)說明,后面的章節(jié)會(huì)逐步更新相關(guān)代碼分析。