我們知道啡专,Glide和Picasso是兩個非常優(yōu)秀的圖片加載框架冲杀,本篇先分析Picasso的源碼,后面再用一篇文對Glide進行分析身堡。兩者的使用方式雖然差不多邓尤,但源碼實現(xiàn)有很大不同,下面先對兩者做一個對比贴谎,然后再分析Picasso源碼:
Glide和Picasso對比
- Picasso代碼體積要比 Glide小很多汞扎;
- Picasso緩存完整大小圖片到本地,Glide則根據(jù)不同控件大小擅这,緩存多張圖片澈魄;
- Picasso占用更大緩存;
- 未緩存前仲翎,Picasso加載速度更快痹扇,緩存后,則Glide更快溯香;
- Glide可以加載Gif和視頻縮略圖鲫构,Picasso則不能。
示例
Picasso.get()
.load( "http://vxKM8h8Hx2wWx3xW.jpg" )
.placeholder( R.drawable.ic_launcher_background )
.error( R.drawable.ic_launcher_background )
.resize( 480,480 )
.centerCrop()
.rotate( 360 )
.priority( Picasso.Priority.HIGH )
.tag( "tag" )
.memoryPolicy( MemoryPolicy.NO_CACHE )
.networkPolicy( NetworkPolicy.NO_CACHE )
.into( ivImage );
源碼分析
public static Picasso get() {
if (singleton == null) {
synchronized (Picasso.class) {
if (singleton == null) {
if (PicassoProvider.context == null) {
throw new IllegalStateException("context == null");
}
singleton = new Builder(PicassoProvider.context).build();
}
}
}
return singleton;
}
Picassso使用的也是雙重鎖檢測的單例模式玫坛,并且用Builder構建模式來構造结笨,這種創(chuàng)建模式在前面幾篇源碼分析已見過多次了。來看Builder如何構造的湿镀。
public class Picasso {
......
public static class Builder {
//上下文
private final Context context;
.....
//構造方法
public Builder(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("Context must not be null.");
}
this.context = context.getApplicationContext();
}
public Picasso build() {
Context context = this.context;
//使用ok下載
if (downloader == null) {
downloader = new OkHttp3Downloader(context);
}
//lru緩存
if (cache == null) {
cache = new LruCache(context);
}
//線程池
if (service == null) {
service = new PicassoExecutorService();
}
//請求轉(zhuǎn)換器
if (transformer == null) {
transformer = RequestTransformer.IDENTITY;
}
//緩存狀態(tài)
Stats stats = new Stats(cache);
//分發(fā)器
Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);
//構造Picasso
return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,
defaultBitmapConfig, indicatorsEnabled, loggingEnabled);
}
}
Builder構造方法只接收一個上下文禀梳,并且獲取的是Application的上下文,這樣做可以防止內(nèi)存泄漏肠骆∷阃荆看到build方法知道,Picasso用的是OkHttp框架來進行加載的蚀腿。
在方法最后有一個Dispatcher 類嘴瓤,它是Picasso的核心類,在構造時傳遞了一個HANDLER對象莉钙,為主線程Handler廓脆,這個對象我們后面再進行分析。而在Dispatcher 內(nèi)部還將創(chuàng)建一個子線程Handler對象磁玉,因此停忿,Dispatcher 將持有主線程Handler和子線程Handler,完成主線程和子線程的切換蚊伞,下面先分析Dispatcher的創(chuàng)建席赂。
class Dispatcher {
......
//子線程
final DispatcherThread dispatcherThread;
//子線程Handler
final Handler handler;
//主線程Handler
final Handler mainThreadHandler;
......
Dispatcher(Context context, ExecutorService service, Handler mainThreadHandler,
Downloader downloader, Cache cache, Stats stats) {
//創(chuàng)建DispatcherThread線程吮铭,并開啟
this.dispatcherThread = new DispatcherThread();
this.dispatcherThread.start();
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 LinkedHashSet<>();
//子線程Handler
this.handler = new DispatcherHandler(dispatcherThread.getLooper(), this);
this.downloader = downloader;
//主線程Handler
this.mainThreadHandler = mainThreadHandler;
this.cache = cache;
this.stats = stats;
this.batch = new ArrayList<>(4);
this.airplaneMode = Utils.isAirplaneModeOn(this.context);
this.scansNetworkChanges = hasPermission(context, Manifest.permission.ACCESS_NETWORK_STATE);
//網(wǎng)絡監(jiān)聽廣播
this.receiver = new NetworkBroadcastReceiver(this);
receiver.register();
}
......
static class DispatcherThread extends HandlerThread {
DispatcherThread() {
super(Utils.THREAD_PREFIX + DISPATCHER_THREAD_NAME, THREAD_PRIORITY_BACKGROUND);
}
}
......
}
DispatcherThread是Dispatcher的靜態(tài)內(nèi)部類,它繼承HandlerThread颅停。
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private Handler mHandler;
public HandlerThread(String name, int priority) {
super(name);
this.mPriority = priority;
}
protected void onLooperPrepared() {
}
//run方法
public void run() {
//得到當前線程id
this.mTid = Process.myTid();
//獲取Looper谓晌,并保存
Looper.prepare();
synchronized(this) {
//獲取當前線程Looper
this.mLooper = Looper.myLooper();
//喚醒線程
this.notifyAll();
}
Process.setThreadPriority(this.mPriority);
this.onLooperPrepared();
//開始消息循環(huán)
Looper.loop();
this.mTid = -1;
}
//獲取Looper
public Looper getLooper() {
if (!this.isAlive()) {
return null;
} else {
synchronized(this) {
//線程活著,Looper未創(chuàng)建
while(this.isAlive() && this.mLooper == null) {
try {
//Looper未創(chuàng)建癞揉,阻塞
this.wait();
} catch (InterruptedException var4) {
}
}
}
return this.mLooper;
}
}
//獲取當前線程Handler
public Handler getThreadHandler() {
if (this.mHandler == null) {
this.mHandler = new Handler(this.getLooper());
}
return this.mHandler;
}
.....
}
HandlerThread是系統(tǒng)實現(xiàn)的一個線程類纸肉,在《Handler,Looper喊熟,Message》以及《ThreadLocal》中已經(jīng)有詳細的分析柏肪,在這里,HandlerThread作為單獨使用芥牌,用于子線程的消息循環(huán)烦味。
由Dispatcher的構造方法看到,它持有了兩個Handler胳泉,一個是主線程的Handler拐叉,一個是關聯(lián)HandlerThread的Looper所得到的,子線程Handler扇商。主線程Handler凤瘦,在上面分析Builder的build方法時提過,將其傳遞給了Dispatcher案铺。
public class Picasso {
......
static final Handler HANDLER = new Handler(Looper.getMainLooper()) {
@Override public void handleMessage(Message msg) {
......
}
}
}
class Dispatcher {
......
private static class DispatcherHandler extends Handler {
private final Dispatcher dispatcher;
DispatcherHandler(Looper looper, Dispatcher dispatcher) {
super(looper);
this.dispatcher = dispatcher;
}
在構造方法最后蔬芥,創(chuàng)建了一個NetworkBroadcastReceiver對象,它是用來監(jiān)聽當前網(wǎng)絡情況的廣播控汉。我們先來看它的實現(xiàn)笔诵。
class Dispatcher {
static final int NETWORK_STATE_CHANGE = 9;
......
static class NetworkBroadcastReceiver extends BroadcastReceiver {
static final String EXTRA_AIRPLANE_STATE = "state";
//持有分發(fā)器
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);
//調(diào)用dispatcher的dispatchNetworkStateChange方法
dispatcher.dispatchNetworkStateChange(connectivityManager.getActiveNetworkInfo());
}
}
}
......
//向子線程Handler發(fā)送NetworkInfo
void dispatchNetworkStateChange(NetworkInfo info) {
handler.sendMessage(handler.obtainMessage(NETWORK_STATE_CHANGE, info));
}
......
網(wǎng)絡有變化情況下,廣播將接收到消息姑子。網(wǎng)絡正常連接情況下乎婿,將通過Dispatcher的dispatchNetworkStateChange方法,向子線程Handler發(fā)送編號為NETWORK_STATE_CHANGE的消息體街佑。上面分析知道谢翎,這個Handler為DispatcherHandler對象。
class Dispatcher {
......
private static class DispatcherHandler extends Handler {
private final Dispatcher dispatcher;
......
case NETWORK_STATE_CHANGE: {
NetworkInfo info = (NetworkInfo) msg.obj;
dispatcher.performNetworkStateChange(info);
break;
}
......
}
//處理網(wǎng)絡變化
void performNetworkStateChange(NetworkInfo info) {
//是否PicassoExecutorService線程池
if (service instanceof PicassoExecutorService) {
((PicassoExecutorService) service).adjustThreadCount(info);
}
if (info != null && info.isConnected()) {
flushFailedActions();
}
}
如果使用了PicassoExecutorService線程池沐旨,將調(diào)用線程池的adjustThreadCount方法森逮,我們看它做了什么工作。
class PicassoExecutorService extends ThreadPoolExecutor {
//默認核心數(shù)為3
private static final int DEFAULT_THREAD_COUNT = 3;
PicassoExecutorService() {
super(DEFAULT_THREAD_COUNT, DEFAULT_THREAD_COUNT, 0, TimeUnit.MILLISECONDS,
new PriorityBlockingQueue<Runnable>(), new Utils.PicassoThreadFactory());
}
void adjustThreadCount(NetworkInfo info) {
if (info == null || !info.isConnectedOrConnecting()) {
setThreadCount(DEFAULT_THREAD_COUNT);
return;
}
switch (info.getType()) {
case ConnectivityManager.TYPE_WIFI: //wifi
case ConnectivityManager.TYPE_WIMAX:
case ConnectivityManager.TYPE_ETHERNET://以太網(wǎng)
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);
}
}
//設置核心數(shù)和最大線程池數(shù)
private void setThreadCount(int threadCount) {
setCorePoolSize(threadCount);
setMaximumPoolSize(threadCount);
}
adjustThreadCount會根據(jù)當前網(wǎng)絡的連接情況磁携,設置線程的核心數(shù)和最大線程池數(shù)褒侧。
回到Builder類,build方法被調(diào)用,在最后創(chuàng)建分發(fā)器Dispatcher對象后闷供,便開始構建Picasso 對象烟央,
public class Picasso {
......
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);
//RequestHandler集合
List<RequestHandler> allRequestHandlers = new ArrayList<>(builtInHandlers + extraCount);
//添加不同的RequestHandler
allRequestHandlers.add(new ResourceRequestHandler(context));
if (extraRequestHandlers != null) {
allRequestHandlers.addAll(extraRequestHandlers);
}
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);
......
}
allRequestHandlers 列表保存了不同的RequestHandler。從命名可以知道这吻,根據(jù)不同的源吊档,將使用不同的RequestHandler來加載圖片篙议。比如唾糯,當我們從網(wǎng)絡獲取一張圖片時,將使用NetworkRequestHandler來進行加載鬼贱。
通過靜態(tài)get()方法便得到了構建的Picasso 對象移怯,接著我們調(diào)用load()方法,傳入圖片的加載路徑这难。
public class Picasso {
......
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));
}
//封裝地址為Uri舟误,并構建RequestCreator
public RequestCreator load(@Nullable Uri uri) {
return new RequestCreator(this, uri, 0);
}
......
}
load方法返回了RequestCreator對象,見名知義姻乓,我們可以看出它是用來創(chuàng)建Request對象的嵌溢。我們先看它的構造方法。
public class RequestCreator {
......
private final Picasso picasso;
private final Request.Builder data;
......
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;
//創(chuàng)建了Request.Builder
this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);
}
......
}
RequestCreator的構造方法做了兩個操作蹋岩,將Picasso 保存到成員變量中赖草,并將uri, resourceId, picasso.defaultBitmapConfig三個參數(shù),傳遞給Request.Builder剪个。像裁剪秧骑、旋轉(zhuǎn)、根據(jù)控件縮放都是通過Request.Builder來操作的扣囊,在這里乎折,它的還尚未執(zhí)行build方法來構建Request,而是在into方法中被構建的侵歇,因為骂澄,在沒有準備好執(zhí)行請求前,無需提前創(chuàng)建惕虑,消耗資源坟冲。
那么,接著來看into方法是如何獲取圖片枷遂,并設置到我們指定的控件中的樱衷。
public class RequestCreator {
.......
//調(diào)用重載into
public void into(ImageView target) {
into(target, null);
}
//重載into
public void into(ImageView target, Callback callback) {
long started = System.nanoTime();
checkMain();
//控件不能為null
if (target == null) {
throw new IllegalArgumentException("Target must not be null.");
}
//如果url為null或resourceId為0,則取消請求
if (!data.hasImage()) {
//取消請求
picasso.cancelRequest(target);
//顯示設置的占位圖片
if (setPlaceholder) {
setPlaceholder(target, getPlaceholderDrawable());
}
return;
}
//是否設置fit酒唉,用于延遲
if (deferred) {
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) {
if (setPlaceholder) {
setPlaceholder(target, getPlaceholderDrawable());
}
//創(chuàng)建DeferredRequestCreator
picasso.defer(target, new DeferredRequestCreator(this, target, callback));
return;
}
data.resize(width, height);
}
//創(chuàng)建Request
Request request = createRequest(started);
//將Request參數(shù)構建成一個字符串矩桂,作為key
String requestKey = createKey(request);
//從緩存獲取圖片
if (shouldReadFromMemoryCache(memoryPolicy)) {
Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
//如果緩存圖片存在
if (bitmap != null) {
//取消請求
picasso.cancelRequest(target);
setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled);
if (picasso.loggingEnabled) {
log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY);
}
//成功回調(diào)
if (callback != null) {
callback.onSuccess();
}
return;
}
}
if (setPlaceholder) {
setPlaceholder(target, getPlaceholderDrawable());
}
//緩存沒有命中,則構建一個Action
Action action =
new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,
errorDrawable, requestKey, tag, callback, noFade);
//提交請求
picasso.enqueueAndSubmit(action);
}
//創(chuàng)建Request
private Request createRequest(long started) {
int id = nextId.getAndIncrement();
//執(zhí)行Request.Builder的build方法,構建Request
Request request = data.build();
request.id = id;
request.started = started;
boolean loggingEnabled = picasso.loggingEnabled;
if (loggingEnabled) {
log(OWNER_MAIN, VERB_CREATED, request.plainId(), request.toString());
}
//如果沒有設置變換Request將不做變化返回
Request transformed = picasso.transformRequest(request);
if (transformed != request) {
transformed.id = id;
transformed.started = started;
if (loggingEnabled) {
log(OWNER_MAIN, VERB_CHANGED, transformed.logId(), "into " + transformed);
}
}
//返回Request
return transformed;
}
}
into方法主要進行3個判斷:
判斷是否設置fit 屬性侄榴,如果設置了雹锣,嘗試獲取ImageView 的寬高,如果獲取不到癞蚕,生成一個DeferredRequestCreator(延遲的請求管理器)蕊爵,在DeferredRequestCreator中當監(jiān)聽到可以獲取ImageView 的寬高的時候,再執(zhí)行into方法桦山。
判斷是否從內(nèi)存緩存獲取圖片攒射,如果沒有設置NO_CACHE,則從內(nèi)存獲取,命中直接回調(diào)CallBack 并且顯示圖片恒水。
如果緩存未命中会放,代碼執(zhí)行到最后,會生成一個Action并提交钉凌,用于網(wǎng)絡請求咧最。
每一個 Target 同一時刻只對應一個 Action,當同一個 Target 有新的請求時御雕,當前 Action 會被取消掉矢沿,這可以解決列表復用錯亂問題。它的實現(xiàn)子類為ImageViewAction酸纲。
abstract class Action<T> {
//弱引用
static class RequestWeakReference<M> extends WeakReference<M> {
final Action action;
RequestWeakReference(Action action, M referent, ReferenceQueue<? super M> q) {
super(referent, q);
this.action = action;
}
}
......
final WeakReference<T> target;
......
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;
//將target包裝為弱引用
this.target =
target == null ? null : new RequestWeakReference<>(this, target, picasso.referenceQueue);
......
}
abstract void complete(Bitmap result, Picasso.LoadedFrom from);
abstract void error(Exception e);
......
}
class ImageViewAction extends Action<ImageView> {
Callback callback;
ImageViewAction(Picasso picasso, ImageView imageView, Request data, int memoryPolicy,
int networkPolicy, int errorResId, Drawable errorDrawable, String key, Object tag,
Callback callback, boolean noFade) {
super(picasso, imageView, data, memoryPolicy, networkPolicy, errorResId, errorDrawable, key,
tag, noFade);
this.callback = callback;
}
@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
ImageView target = this.target.get();
if (target == null) {
return;
}
Context context = picasso.context;
boolean indicatorsEnabled = picasso.indicatorsEnabled;
//設置圖片到ImageView
PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);
//回調(diào)
if (callback != null) {
callback.onSuccess();
}
}
Action對象用一個弱應用封裝了Target捣鲸。當
public class Picasso {
//Action緩存集合
final Map<Object, Action> targetToAction;
......
void enqueueAndSubmit(Action action) {
//獲取Target
Object target = action.getTarget();
//target 是否關聯(lián)了其他action,如果不相等福青,說明關聯(lián)了
if (target != null && targetToAction.get(target) != action) {
// 先取消之前的關聯(lián)
cancelExistingRequest(target);
//重新關聯(lián)映射
targetToAction.put(target, action);
}
//提交Action
submit(action);
}
}
將Action提交給Picasso 的enqueueAndSubmit后摄狱,會先判斷當前的Target是否已關聯(lián)了其他Action,如果是的話无午,通過cancelExistingRequest(target)方法媒役,將之前的關聯(lián)取消,再將Target和提交過來的Action重新關聯(lián)宪迟,并緩存起來酣衷。那么,cancelExistingRequest(target)是如何取消它們的關聯(lián)的呢次泽。
//取消Target的請求
void cancelExistingRequest(Object target) {
//檢查是否在主線程
checkMain();
//從緩存中移除target對應的action
Action action = targetToAction.remove(target);
if (action != null) {
//將Action的cancelled置為true穿仪,如果有設置callback,則callback置null
action.cancel();
//分發(fā)器執(zhí)行取消操作
dispatcher.dispatchCancel(action);
}
//如果是Target是ImageView意荤,則從DeferredRequestCreator 移除
if (target instanceof ImageView) {
ImageView targetImageView = (ImageView) target;
DeferredRequestCreator deferredRequestCreator =
targetToDeferredRequestCreator.remove(targetImageView);
if (deferredRequestCreator != null) {
deferredRequestCreator.cancel();
}
}
將Action從緩存移除后啊片,主要是通過Dispatcher 分發(fā)器來取消Action的其他執(zhí)行流程。Dispatcher 通過子線程DispatcherHandler對象來處理玖像。
class Dispatcher {
//BitmapHunter緩存
final Map<String, BitmapHunter> hunterMap;
......
//發(fā)送取消消息
void dispatchCancel(Action action) {
handler.sendMessage(handler.obtainMessage(REQUEST_CANCEL, action));
}
//子線程Handler
private static class DispatcherHandler extends Handler {
private final Dispatcher dispatcher;
@Override public void handleMessage(final Message msg) {
switch (msg.what) {
......
case REQUEST_CANCEL: {
Action action = (Action) msg.obj;
dispatcher.performCancel(action);
break;
}
}}
}
//執(zhí)行Action 具體取消操作
void performCancel(Action action) {
//獲取key
String key = action.getKey();
//根據(jù)key獲取BitmapHunter 紫谷,它是一個Runnable
BitmapHunter hunter = hunterMap.get(key);
if (hunter != null) {
//從BitmapHunter 的actions列表移除Action
hunter.detach(action);
if (hunter.cancel()) {
hunterMap.remove(key);
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_CANCELED, action.getRequest().logId());
}
}
}
// 如果在 pause 隊列中,則移除
if (pausedTags.contains(action.getTag())) {
pausedActions.remove(action.getTarget());
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_CANCELED, action.getRequest().logId(),
"because paused request got canceled");
}
}
// 失敗隊列中包含了,也移除
Action remove = failedActions.remove(action.getTarget());
if (remove != null && remove.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_CANCELED, remove.getRequest().logId(), "from replaying");
}
}
BitmapHunter實現(xiàn)了Runnable笤昨,而上面分析Dispatcher構造過程時知道祖驱,Dispatcher對象的成員變量service,持有線程池ExecutorService應用瞒窒,BitmapHunter將作為其執(zhí)行單位捺僻。
我們回到enqueueAndSubmit中的submit(action)方法。action 將被提交給Dispatcher崇裁,Dispatcher則又進一步通過DispatcherHandler 來處理消息匕坯。
public class Picasso {
......
void submit(Action action) {
dispatcher.dispatchSubmit(action);
}
class Dispatcher {
......
void dispatchSubmit(Action action) {
handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action));
}
//子線程Handler
private static class DispatcherHandler extends Handler {
private final Dispatcher dispatcher;
@Override public void handleMessage(final Message msg) {
switch (msg.what) {
case REQUEST_SUBMIT: {
Action action = (Action) msg.obj;
dispatcher.performSubmit(action);
break;
}
}}
void performSubmit(Action action) {
performSubmit(action, true);
}
void performSubmit(Action action, boolean dismissFailed) {
// 查看保存暫停tag表里面沒有包含Action的tag,如果包含,則將Action 存到暫停Action表里
if (pausedTags.contains(action.getTag())) {
pausedActions.put(action.getTarget(), action);
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_PAUSED, action.request.logId(),
"because tag '" + action.getTag() + "' is paused");
}
return;
}
//已經(jīng)提交過寇壳,從hunterMap中獲取
BitmapHunter hunter = hunterMap.get(action.getKey());
if (hunter != null) {
hunter.attach(action);
return;
}
//線程池被關閉了
if (service.isShutdown()) {
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
}
return;
}
//創(chuàng)建一個新的BitmapHunter
hunter = forRequest(action.getPicasso(), this, cache, stats, action);
//BitmapHunter 提交給線程池
hunter.future = service.submit(hunter);
//根據(jù)Key緩存在hunterMap中
hunterMap.put(action.getKey(), hunter);
if (dismissFailed) {
failedActions.remove(action.getTarget());
}
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
}
}
}
performSubmit中關鍵的邏輯是醒颖,創(chuàng)建 BitmapHunter 并提交給線程池ExecuteService妻怎。forRequest 方法構建了一個BitmapHunter 壳炎,在構建過程中需要為BitmapHunter 指定對應的處理器,即我們前面提到過的RequestHandler逼侦。
class BitmapHunter implements Runnable {
......
//獲取BitmapHunter
static BitmapHunter forRequest(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats,
Action action) {
//獲取Request
Request request = action.getRequest();
List<RequestHandler> requestHandlers = picasso.getRequestHandlers();
//遍歷requestHandlers 列表
for (int i = 0, count = requestHandlers.size(); i < count; i++) {
RequestHandler requestHandler = requestHandlers.get(i);
//查看那種RequestHandler能處理這個請求
if (requestHandler.canHandleRequest(request)) {
//將對應的RequestHandler 封裝到BitmapHunter中返回
return new BitmapHunter(picasso, dispatcher, cache, stats, action, requestHandler);
}
}
//如果獲取到合適的RequestHandler 則ERRORING_HANDLER
return new BitmapHunter(picasso, dispatcher, cache, stats, action, ERRORING_HANDLER);
}
}
這里假設通過網(wǎng)絡獲取圖片匿辩,那么將匹配到NetworkRequestHandler,那么它的canHandleRequest方法是如何比對request榛丢,以決定使用NetworkRequestHandler處理器的铲球。
class NetworkRequestHandler extends RequestHandler {
private static final String SCHEME_HTTP = "http";
private static final String SCHEME_HTTPS = "https";
//判斷是否使用當前處理器
@Override public boolean canHandleRequest(Request data) {
String scheme = data.uri.getScheme();
return (SCHEME_HTTP.equals(scheme) || SCHEME_HTTPS.equals(scheme));
}
......
}
邏輯很簡單,判斷scheme 是否為http或https晰赞。
到這里BitmapHunter構建成功后稼病,被提交給了Dispatcher 的線程池調(diào)用,也就是說掖鱼,后續(xù)請求的邏輯將在BitmapHunter的run方法中執(zhí)行然走。
class BitmapHunter implements Runnable {
//保存為位圖
Bitmap result;
......
@Override public void run() {
try {
updateThreadName(data);
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_EXECUTING, getLogIdsForHunter(this));
}
//具體獲取邏輯又被封裝成hunt方法
result = hunt();
//result為null,分發(fā)失敗
if (result == null) {
dispatcher.dispatchFailed(this);
} else {
//result不為null戏挡,顯示圖片
dispatcher.dispatchComplete(this);
}
} catch (NetworkRequestHandler.ResponseException e) {
if (!NetworkPolicy.isOfflineOnly(e.networkPolicy) || e.code != 504) {
exception = e;
}
dispatcher.dispatchFailed(this);
} catch (IOException e) {
exception = e;
dispatcher.dispatchRetry(this);
} catch (OutOfMemoryError e) {
StringWriter writer = new StringWriter();
stats.createSnapshot().dump(new PrintWriter(writer));
exception = new RuntimeException(writer.toString(), e);
dispatcher.dispatchFailed(this);
} catch (Exception e) {
exception = e;
dispatcher.dispatchFailed(this);
} finally {
Thread.currentThread().setName(Utils.THREAD_IDLE_NAME);
}
}
//獲取Bitmap
Bitmap hunt() throws IOException {
Bitmap bitmap = null;
// 從內(nèi)存緩存獲取Bitmap
if (shouldReadFromMemoryCache(memoryPolicy)) {
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;
//處理器加載
RequestHandler.Result result = requestHandler.load(data, networkPolicy);
if (result != null) {
loadedFrom = result.getLoadedFrom();
exifOrientation = result.getExifOrientation();
bitmap = result.getBitmap();
//重新解碼源
if (bitmap == null) {
Source source = result.getSource();
try {
bitmap = decodeStream(source, data);
} finally {
try {
source.close();
} catch (IOException ignored) {
}
}
}
}
......
return bitmap;
}
如果緩存中沒有獲取到Bitmap,則將通過處理器NetworkRequestHandler 的load方法從網(wǎng)絡進行加載褐墅。如果Bitmap獲取成功拆檬,將通過dispatchComplete方法將Bitamp設置到控件中。我們先分析Bitmap從網(wǎng)絡獲取的流程妥凳。
class NetworkRequestHandler extends RequestHandler {
private final Downloader downloader;
......
@Override public Result load(Request request, int networkPolicy) throws IOException {
okhttp3.Request downloaderRequest = createRequest(request, networkPolicy);
//上面分析知道竟贯,downloader實際為OkHttp3Downloader
Response response = downloader.load(downloaderRequest);
ResponseBody body = response.body();
......
return new Result(body.source(), loadedFrom);
}
在最新的Picasso源碼中,OkHttp3Downloader已經(jīng)是Downloader 的唯一實現(xiàn)類逝钥,原來的UrlConnectionDownloader 已經(jīng)被移除調(diào)了屑那。
public final class OkHttp3Downloader implements Downloader {
.....
@NonNull @Override public Response load(@NonNull Request request) throws IOException {
return client.newCall(request).execute();
}
......
}
OkHttp3Downloader通過同步請求進行圖片下載,OkHttp的具體源碼執(zhí)行流程已分析過,這里不做贅述齐莲。
從網(wǎng)絡下載后痢站,Source將被解析成Bitmap,并返回給BitmapHunter 的成員變量result选酗,緊接著調(diào)用Dispatcher的dispatchComplete方法阵难,展示到控件中。
class Dispatcher {
......
final List<BitmapHunter> batch;
private static final int BATCH_DELAY = 200; // ms
......
void dispatchComplete(BitmapHunter hunter) {
handler.sendMessage(handler.obtainMessage(HUNTER_COMPLETE, hunter));
}
private static class DispatcherHandler extends Handler {
private final Dispatcher dispatcher;
DispatcherHandler(Looper looper, Dispatcher dispatcher) {
super(looper);
this.dispatcher = dispatcher;
}
@Override public void handleMessage(final Message msg) {
.......
//從BitmapHunter 獲取Bitmap
case HUNTER_COMPLETE: {
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performComplete(hunter);
break;
}
//批量處理Bitmap
case HUNTER_DELAY_NEXT_BATCH: {
dispatcher.performBatchComplete();
break;
}
}
void performComplete(BitmapHunter hunter) {
//如果我們設置了緩存芒填,則將Bitmap緩存起來
if (shouldWriteToMemoryCache(hunter.getMemoryPolicy())) {
cache.set(hunter.getKey(), hunter.getResult());
}
//將BitmapHunter移除掉
hunterMap.remove(hunter.getKey());
batch(hunter);
if (hunter.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_BATCHED, getLogIdsForHunter(hunter), "for completion");
}
}
private void batch(BitmapHunter hunter) {
//cancel為true就不展示了
if (hunter.isCancelled()) {
return;
}
if (hunter.result != null) {
hunter.result.prepareToDraw();
}
//將hunter添加到列表中
batch.add(hunter);
//消息列表中沒有HUNTER_DELAY_NEXT_BATCH的類型
if (!handler.hasMessages(HUNTER_DELAY_NEXT_BATCH)) {
handler.sendEmptyMessageDelayed(HUNTER_DELAY_NEXT_BATCH, BATCH_DELAY);
}
}
void performBatchComplete() {
//將batch拷貝一份
List<BitmapHunter> copy = new ArrayList<>(batch);
//清理掉原來的list
batch.clear();
//將拷貝后的List發(fā)送給主線程Handler
mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(HUNTER_BATCH_COMPLETE, copy));
logBatch(copy);
}
}
因為可能存在多個圖片同時下載完成的情況呜叫,因此,在向主線程發(fā)送消息前殿衰,會將接收到的BitmapHunter集中添加到List中朱庆,一起發(fā)送給主線程的Handler進行處理。由上面分析知道闷祥,這個mainThreadHandler在Picasso 中娱颊,在構造Dispatcher對象時被傳遞進來。我們看它消息類型為HUNTER_BATCH_COMPLETE是如何處理圖片的展示的凯砍。
public class Picasso {
......
static final Handler HANDLER = new Handler(Looper.getMainLooper()) {
@Override public void handleMessage(Message msg) {
switch (msg.what) {
case HUNTER_BATCH_COMPLETE: {
//獲取到BitmapHunter列表箱硕,進行遍歷
@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;
}
.....
}
};
void complete(BitmapHunter hunter) {
//獲取Action
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();
//將Action 傳遞給deliverAction
if (single != null) {
deliverAction(result, from, single, exception);
}
......
}
private void deliverAction(Bitmap result, LoadedFrom from, Action action, Exception e) {
if (action.isCancelled()) {
return;
}
if (!action.willReplay()) {
targetToAction.remove(action.getTarget());
}
if (result != null) {
if (from == null) {
throw new AssertionError("LoadedFrom cannot be null.");
}
//調(diào)用action的complete設置圖片
action.complete(result, from);
if (loggingEnabled) {
log(OWNER_MAIN, VERB_COMPLETED, action.request.logId(), "from " + from);
}
} else {
action.error(e);
if (loggingEnabled) {
log(OWNER_MAIN, VERB_ERRORED, action.request.logId(), e.getMessage());
}
}
}
}
主線程的HANDLER 接收到BitmapHunter列表后,進行遍歷悟衩,并將Bitmap傳遞給對應Action的complete方法剧罩,將其設置到Target中,在示例中我們傳遞了ImageView座泳,因此锁施,Action的實際實現(xiàn)類為ImageViewAction挚冤,我們看它的complete方法。
class ImageViewAction extends Action<ImageView> {
......
@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
ImageView target = this.target.get();
if (target == null) {
return;
}
Context context = picasso.context;
boolean indicatorsEnabled = picasso.indicatorsEnabled;
//通過PicassoDrawable設置Bitmap
PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);
if (callback != null) {
callback.onSuccess();
}
}
}
final class PicassoDrawable extends BitmapDrawable {
......
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();
}
//將Bitmap轉(zhuǎn)為PicassoDrawable
PicassoDrawable drawable =
new PicassoDrawable(context, bitmap, placeholder, loadedFrom, noFade, debugging);
target.setImageDrawable(drawable);
}
......
}
BitmapDrawable繼承自BitmapDrawable ,最終將Bitmap轉(zhuǎn)為PicassoDrawable 审磁,設置到target中没炒,即ImageView 帜矾,到此豺型,圖片就顯示到我們的屏幕上了。