首先了解下涉及的类及它们之间的关系。
简单使用
Picasso.with(this).load("").into(new ImageView(this));
with:
static volatile Picasso singleton = null;
public static Picasso with(Context context) {
if (singleton == null) {
synchronized (Picasso.class) {
if (singleton == null) {
// 注意build方法
singleton = new Builder(context).build();
}
}
}
return singleton;
}
该对象是单例模式,DCL 双重检查锁模式,自身对象是通过建造者模式创建。注意build方法。
/** Create the {@link Picasso} instance. */
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);
}
}
下载器:createDefaultDownloader 首先判断是否有okhttp 库,如果没有使用UrlConnectionDownloader对象,其实就是httpurlConnection对象处理请求。
static Downloader createDefaultDownloader(Context context) {
try {
Class.forName("com.squareup.okhttp.OkHttpClient");
return OkHttpLoaderCreator.create(context);
} catch (ClassNotFoundException ignored) {
}
return new UrlConnectionDownloader(context);
}
Cache: 缓存对象,内部通过linkedHashMap来实现LruCache(最近最少被使用),这地方不多做说明。
/** Create a cache with a given maximum size in bytes. */
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("Max size must be positive.");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);
}
PicassoExecutorService 线程池对象
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize, // 最大线程池数量
long keepAliveTime,// 存活时间
TimeUnit unit,// 单元
BlockingQueue<Runnable> workQueue, // 队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler) {
Dispatcher 分发器,负责处理多种消息,取消任务,提交任务等
HANDLER: 静态handler类,接受消息并处理
new Picasso() 真实创建的主对象。
Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);
return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,
defaultBitmapConfig, indicatorsEnabled, loggingEnabled);
接下来看下dispatcher的构造
Dispatcher(Context context, ExecutorService service, Handler mainThreadHandler,
Downloader downloader, Cache cache, Stats stats) {
this.dispatcherThread = new DispatcherThread();
this.dispatcherThread.start(); // handlerThread
Utils.flushStackLocalLeaks(dispatcherThread.getLooper());
this.context = context;
this.service = service;
this.hunterMap = new LinkedHashMap<String, BitmapHunter>();
this.failedActions = new WeakHashMap<Object, Action>();
this.pausedActions = new WeakHashMap<Object, Action>();
this.pausedTags = new HashSet<Object>();
// 分发任务的handler,传入handlerThread的looper对象
this.handler = new DispatcherHandler(dispatcherThread.getLooper(), this);
this.downloader = downloader;
this.mainThreadHandler = mainThreadHandler;// 主线程的handler
this.cache = cache;
this.stats = stats;
this.batch = new ArrayList<BitmapHunter>(4);
this.airplaneMode = Utils.isAirplaneModeOn(this.context);
this.scansNetworkChanges = hasPermission(context, Manifest.permission.ACCESS_NETWORK_STATE);
this.receiver = new NetworkBroadcastReceiver(this);// 监测网络变化的广播
receiver.register();
}
static class DispatcherThread extends HandlerThread {
DispatcherThread() {
super(Utils.THREAD_PREFIX + DISPATCHER_THREAD_NAME, THREAD_PRIORITY_BACKGROUND);
}
}
private static class DispatcherHandler extends Handler {
private final Dispatcher dispatcher;
public DispatcherHandler(Looper looper, Dispatcher dispatcher) {
super(looper);
this.dispatcher = dispatcher;
}
@Override public void handleMessage(final Message msg) {
switch (msg.what) {
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);
}
});
}
}
}
最后看下picasso的构造
Picasso(Context context, Dispatcher dispatcher, Cache cache, Listener listener,
RequestTransformer requestTransformer, List<RequestHandler> extraRequestHandlers, Stats stats,
Bitmap.Config defaultBitmapConfig, boolean indicatorsEnabled, boolean loggingEnabled) {
....省略
int builtInHandlers = 7; // Adjust this as internal handlers are added or removed.
int extraCount = (extraRequestHandlers != null ? extraRequestHandlers.size() : 0);
List<RequestHandler> allRequestHandlers =
new ArrayList<RequestHandler>(builtInHandlers + extraCount);
// ResourceRequestHandler needs to be the first in the list to avoid
// forcing other RequestHandlers to perform null checks on request.uri
// to cover the (request.resourceId != 0) case.
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);
this.stats = stats;
this.targetToAction = new WeakHashMap<Object, Action>();
this.targetToDeferredRequestCreator = new WeakHashMap<ImageView, DeferredRequestCreator>();
this.indicatorsEnabled = indicatorsEnabled;
this.loggingEnabled = loggingEnabled;
this.referenceQueue = new ReferenceQueue<Object>();
this.cleanupThread = new CleanupThread(referenceQueue, HANDLER);
this.cleanupThread.start();
}
ContactsPhotoRequestHandler
MediaStoreRequestHandler
ContentStreamRequestHandler
AssetRequestHandler
FileRequestHandler
NetworkRequestHandler
这几种handler 对象不同资源的处理方式。咱们这里只讲网络请求图片的逻辑,所以就只看NetworkRequestHandler. 它有一个load方法是请求网络。downloader网络加载器,前面说过。根据该对象获取Response,通过该对象获取Result对象。
@Override public Result load(Request request, int networkPolicy) throws IOException {
// downloader 就是网络加载器,前面说过。根据该对象获取Response
Response response = downloader.load(request.uri, request.networkPolicy);
if (response == null) {
return null;
}
Picasso.LoadedFrom loadedFrom = response.cached ? DISK : NETWORK;
Bitmap bitmap = response.getBitmap();
if (bitmap != null) {
return new Result(bitmap, loadedFrom);
}
InputStream is = response.getInputStream();
if (is == null) {
return null;
}
// Sometimes response content length is zero when requests are being replayed. Haven't found
// root cause to this but retrying the request seems safe to do so.
if (loadedFrom == DISK && response.getContentLength() == 0) {
Utils.closeQuietly(is);
throw new ContentLengthException("Received response with 0 content-length header.");
}
if (loadedFrom == NETWORK && response.getContentLength() > 0) {
stats.dispatchDownloadFinished(response.getContentLength());
}
return new Result(is, loadedFrom);
}
截止到现在,咱们只是讲了with涉及的主要对象。
接下来开始讲解load 方法
public RequestCreator load(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));
}
public RequestCreator load(Uri uri) {
return new RequestCreator(this, uri, 0);
}
只是创建了一个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;
//request其实就是任务的各个属性封装对象,且使用建造者模式,因此真正创建该对象就要调用build方法。下面会说到。
this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);
}
//builder方法
Builder(Uri uri, int resourceId, Bitmap.Config bitmapConfig) {
this.uri = uri;
this.resourceId = resourceId;
this.config = bitmapConfig;
}
//builder对象封装的各个图片的属性
public static final class Builder {
private Uri uri;
private int resourceId;
private String stableKey;
private int targetWidth;
private int targetHeight;
private boolean centerCrop;
private boolean centerInside;
private boolean onlyScaleDown;
private float rotationDegrees;
private float rotationPivotX;
private float rotationPivotY;
private boolean hasRotationPivot;
private List<Transformation> transformations;
private Bitmap.Config config;
private Priority priority;
...忽略
}
into
public void into(ImageView target, Callback callback) {
long started = System.nanoTime();
checkMain();// check main thread
if (target == null) {
throw new IllegalArgumentException("Target must not be null.");
}
if (!data.hasImage()) {
picasso.cancelRequest(target);
if (setPlaceholder) {
setPlaceholder(target, getPlaceholderDrawable());
}
return;
}
if (deferred) { //delay load
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());
}
picasso.defer(target, new DeferredRequestCreator(this, target, callback));
return;
}
data.resize(width, height);
}
Request request = createRequest(started);//create request 前面讲的图片属性的封装
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);
}
if (callback != null) {
callback.onSuccess();
}
return;
}
}
if (setPlaceholder) {
setPlaceholder(target, getPlaceholderDrawable());
}
// 1处
Action action =
new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,
errorDrawable, requestKey, tag, callback, noFade);
picasso.enqueueAndSubmit(action);
}
1处创建任务活动对象,每一个action 对象对应一次请求。继续往下enqueueAndSubmit
void enqueueAndSubmit(Action action) {
Object target = action.getTarget();
if (target != null && targetToAction.get(target) != action) {
// This will also check we are on the main thread.
cancelExistingRequest(target);
targetToAction.put(target, action);
}
submit(action);//1
}
void submit(Action action) {
dispatcher.dispatchSubmit(action);//2
}
void dispatchSubmit(Action action) {
//3
handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action));
}
case REQUEST_SUBMIT: {
Action action = (Action) msg.obj;
//4
dispatcher.performSubmit(action);
break;
}
void performSubmit(Action action) {
//5
performSubmit(action, true);
}
void performSubmit(Action action, boolean dismissFailed) {
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;
}
//6
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;
}
//7
hunter = forRequest(action.getPicasso(), this, cache, stats, action);
hunter.future = service.submit(hunter);//8
hunterMap.put(action.getKey(), hunter);
if (dismissFailed) {
failedActions.remove(action.getTarget());
}
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
}
}
此处代码多,简言之,通过handler 发送action ,根据action 获取线程任务bitmapHunter对象,该对象就是真正去执行图片的加载对象。最后由线程池对象开启线程。
7处,根据action 获取由哪个handler对象能够处理该任务。
static BitmapHunter forRequest(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats,
Action action) {
Request request = action.getRequest();
List<RequestHandler> requestHandlers = picasso.getRequestHandlers();
// Index-based loop to avoid allocating an iterator.
//noinspection ForLoopReplaceableByForEach
for (int i = 0, count = requestHandlers.size(); i < count; i++) {
RequestHandler requestHandler = requestHandlers.get(i);
if (requestHandler.canHandleRequest(request)) {
return new BitmapHunter(picasso, dispatcher, cache, stats, action, requestHandler);
}
}
return new BitmapHunter(picasso, dispatcher, cache, stats, action, ERRORING_HANDLER);
}
// 注意该方法,由具体子类去处理,所以我们只看网络处理对象
public abstract boolean canHandleRequest(Request data);
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));
}
接下来看线程对象,因为是线程对象,所以只看run
@Override public void run() {
try {
updateThreadName(data);// 更改名字
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_EXECUTING, getLogIdsForHunter(this));
}
result = hunt(); 这里
if (result == null) {
dispatcher.dispatchFailed(this);
} else {
dispatcher.dispatchComplete(this);
}
.... 忽略
Bitmap hunt() throws IOException {
Bitmap bitmap = null;
... 忽略
data.networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy;
// requestHandler 其实即使netWorkRequestHandler。 注意load方法,其实这里已经和上面的load呼应上了,最终得到一个result对象,再转换成bitmap对象。
RequestHandler.Result result = requestHandler.load(data, networkPolicy);
if (result != null) {
loadedFrom = result.getLoadedFrom();
exifRotation = result.getExifOrientation();
bitmap = result.getBitmap();
// If there was no Bitmap then we need to decode it from the stream.
if (bitmap == null) {
InputStream is = result.getStream();
try {
bitmap = decodeStream(is, data);
} finally {
Utils.closeQuietly(is);
}
}
}
if (bitmap != null) {
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_DECODED, data.logId());
}
stats.dispatchBitmapDecoded(bitmap);
if (data.needsTransformation() || exifRotation != 0) {
synchronized (DECODE_LOCK) {
if (data.needsMatrixTransform() || exifRotation != 0) {
bitmap = transformResult(data, bitmap, exifRotation);
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId());
}
}
if (data.hasCustomTransformations()) {
bitmap = applyCustomTransformations(data.transformations, bitmap);
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId(), "from custom transformations");
}
}
}
if (bitmap != null) {
stats.dispatchBitmapTransformed(bitmap);
}
}
}
return bitmap;
}