Picasso--设计思路浅析

Picasso结构图


Paste_Image.png

Picasso流程图


Paste_Image.png

Picasso中的核心类包括Picasso、Dispatcher、BitmapHunter、RequestHandler、Request、Action、Cache等。
Picasso类是一个负责图片下载、变换、缓存的管理器,当它收到一个图片下载请求的时候,它会创建Request并提交给Dispatcher。load负责加载网络图片,into负责把图片显示到组件中。

public void into(ImageView target, Callback callback) {
        …
        ImageViewAction action1 = new ImageViewAction(this.picasso, target, request1, this.memoryPolicy, this.networkPolicy, this.errorResId, this.errorDrawable, requestKey1, this.tag, callback, this.noFade);
        this.picasso.enqueueAndSubmit(action1);
    }
}

可以看到into最后通过picasso.enqueueAndSubmit提交到队列,每一个请求对应一个action,每个图片都会into到组件中,因此会有很多action交给Picasso执行,这时就需要Dispatcher进行分发和执行。

void enqueueAndSubmit(Action action) {
    Object target = action.getTarget();
    if(target != null && this.targetToAction.get(target) != action) {
        this.cancelExistingRequest(target);
        this.targetToAction.put(target, action);
    }
    this.submit(action);
}

void submit(Action action) {
    this.dispatcher.dispatchSubmit(action);
}

Dispatcher是在Picasso被创建前实例化的,并作为picasso的一个成员变量

public Picasso build() {
    Context context = this.context;
    …
    Dispatcher dispatcher = new Dispatcher(context, this.service, Picasso.HANDLER, this.downloader, this.cache, stats);
    …
}

在Dispatcher的构造函数中开启了一个消息循环线程DispatcherThread(DispatcherThread是一个HandlerThread,也就是一个带有Looper的线程),之后用DispatcherThread的Looper实例化了一个Handler,用来处理消息循环线程的所有消息。

Dispatcher(Context context, ExecutorService service, Handler mainThreadHandler, Downloader downloader, Cache cache, Stats stats) {
    this.dispatcherThread.start();
    …
    this.handler = new Dispatcher.DispatcherHandler(this.dispatcherThread.getLooper(), this);
    …
}
final Dispatcher.DispatcherThread dispatcherThread = new Dispatcher.DispatcherThread();
static class DispatcherThread extends HandlerThread {
    DispatcherThread() {
        super("Picasso-Dispatcher", 10);
    }
}

这样Dispatcher的消息循环机制就建立起来了。
根据上面介绍into->picasso.enqueueAndSubmit->submit-> dispatcher.dispatchSubmit

void dispatchSubmit(Action action) {
    this.handler.sendMessage(this.handler.obtainMessage(REQUEST_SUBMIT
, action));
}

可以看到是通过Handler向HandlerThread发消息进行分发的。根据Hander机制,最终消息在Handler的 handlerMessage()回调中被处理, action的其他操作,也通过这种方式进行分发和处理。

public void handleMessage(final Message msg) {
    Object info;
    BitmapHunter info2;
    Action info3;
    switch(msg.what) {
        case REQUEST_SUBMIT:
            info3 = (Action)msg.obj;
            this.dispatcher.performSubmit(info3);
            break;
        …
    }
}

action的执行通过dispatcher.performSubmit

void performSubmit(Action action) {
    this.performSubmit(action, true);
}

void performSubmit(Action action, boolean dismissFailed) {
    //action是否被暂停
    if(this.pausedTags.contains(action.getTag())) {
        …
    } else {
        //从hunter map里查找当前action所关联的hunter,有就直接使用
        BitmapHunter hunter = (BitmapHunter)this.hunterMap.get(action.getKey());
        if(hunter != null) {
            …
        } else if(this.service.isShutdown()) {
            …
    } else {
            //创建BitmapHunter
            hunter = BitmapHunter.forRequest(action.getPicasso(), this, this.cache, this.stats, action);
            //提交到线程池中执行
            hunter.future = this.service.submit(hunter);
            //把此hunter加入到hunter map中
            this.hunterMap.put(action.getKey(), hunter);
            …
        }
    }
}

可以看到这里BitmapHunter出场了,忽略掉异常情况,可以看到是由forRequest()创建该action的BitMapHunter,之后提交到线程池中并加入到hunter map中。
再来看BitMapHunter

class BitmapHunter implements Runnable

可以看到BitmapHunter其实是一个Runnable,在线程池上执行的是其run()方法

Bitmap result;
public void run() {
     …
     this.result = this.hunt();//获得bitmap
     if(this.result == null) {//通过dispatcher分发处理
        this.dispatcher.dispatchFailed(this);
     } else {
        this.dispatcher.dispatchComplete(this);
     }
     …
}

忽略掉异常情况,bitmap是通过hunt这个方法获得的, 然后将结果通过Dispatcher进行分发处理
进入到hunt中看如何获得bitmap

Bitmap hunt() throws IOException {
    Bitmap bitmap = null;
    …
    Result result = this.requestHandler.load(this.data, this.networkPolicy);
    if(result != null) {
        …
        bitmap = result.getBitmap();
        …
    }
    …
    }

    return bitmap;
}

忽略掉异常情况, Bitmap最终是由BitmapHunter的requestHandler.load()方法获取的, Picasso默认提供了ResourceRequestHandler、ContactsPhotoRequestHandler、MediaStoreRequestHandler、ContentStreamRequestHandler、 AssetRequestHandler、FileRequestHandler、NetworkRequestHandler等7中RequestHandler,用来从不同的来源获取Bitmap。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容