Picasso源码初探

Picasso源码初探

  Picasso是Square基于Android平台的开源框架,提供图片加载和缓存功能,官网这样描述:

A powerful image downloading and caching library for Android

  本文基于Picasso 2.6.0-SNAPSHOT版本代码,粗略分析其运行原理。相关网站:Picasso主页github地址

Picasso框架一览

  Picasso使用非常方便,如下:

Picasso.with(context).load("http://sample/image.png").into(imageView);

  Picasso框架使用异步加载的方式加载图片。Picasso类是框架主要入口,其with方法调用Picasso.Builder创建Picasso对象。Builder的build方法中初始化了框架中主要的部件,如下:

public Picasso build() {
    Context context = this.context;
    if (downloader == null) {
        downloader = Utils.createDefaultDownloader(context);  // 设置Downloader
    }
    if (cache == null) {
        cache = new LruCache(context);  //设置缓存
    }
    if (service == null) {
        service = new PicassoExecutorService();  //ExecutorService
    }
    if (transformer == null) {
        transformer = RequestTransformer.IDENTITY;  //Request转换器
    }
    Stats stats = new Stats(cache);  // cache状态
    Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);  // Dispatcher
    return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,
            defaultBitmapConfig, indicatorsEnabled, loggingEnabled);
}

  进行网络下载时,若存在okhttp库,Downloader为OkHttp3Downloader,否则使用HttpUrlConnection。Cache默认使用LruCache。ExecutorService初始化为PicassoExecutorService,PicassoExecutorService继承ThreadPoolExecutor,根据当前安卓平台网络环境设置线程数目。Dispatcher是请求的分发器,负责异步操作的派发和线程的调度。

  Picasso的load方法返回RequestCreator对象。RequestCreator封装Request请求生成过程,并提供一系列方法进行图片操作设置,如resize,fit,rotate。调用into方法后开始加载图片操作。图片加载流程如下:

dispatch

Dispatcher

  Dispatcher在框架中处于枢纽位置,Picasso对象调用dispatchSubmit方法发出请求,Dispatcher存在DispatcherThread对象引用,通过的dispatcherHandler发送消息到dispatcherThread线程,然后调用ExecuteService.submit异步处理请求,并通过dispatcherHandler和回调返回结果。其performSubmit方法实现请求提交过程,如下:

void performSubmit(Action action, boolean dismissFailed) {
    ....  //忽略代码

    BitmapHunter hunter = hunterMap.get(action.getKey());  //  判断action是否存在
    if (hunter != null) {
        hunter.attach(action);
        return;
    }
    // 判断ExecutorSevice是否停止
    if (service.isShutdown()) {
        if (action.getPicasso().loggingEnabled) {
            log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
        }
        return;
    }
    // 生成BitmapHunter对象
    hunter = forRequest(action.getPicasso(), this, cache, stats, action);
    // 提交hunt对象在ExecutorSevice异步运行
    hunter.future = service.submit(hunter);
    hunterMap.put(action.getKey(), hunter);
    if (dismissFailed) {
        failedActions.remove(action.getTarget());
    }

    if (action.getPicasso().loggingEnabled) {
        log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
    }
}

  BitmapHunter实现了加载图片和转换图片的操作。BitmapHunter实现Runnable接口,其主要逻辑实现在于hunt方法,hunt代码如下:

Bitmap hunt() throws IOException {
    Bitmap bitmap = null;

    // 读取cache
    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;
        }
    }

    data.networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy;
    // 调用requestHandler.load加载图片
    RequestHandler.Result result = requestHandler.load(data, networkPolicy);
    if (result != null) {
        loadedFrom = result.getLoadedFrom();
        exifOrientation = result.getExifOrientation();
        bitmap = result.getBitmap();

        // 从InputStream获取bitmap
        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() || exifOrientation != 0) {
            synchronized (DECODE_LOCK) {
                if (data.needsMatrixTransform() || exifOrientation != 0) {
                    bitmap = transformResult(data, bitmap, exifOrientation);
                    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;
}

  BitmapHunter调用RequestHandler.load方法加载图片,在图片加载成功后调用transformResult方法进行图片变换。

RequestHandler

  Picasso支持从本地、网络、content provider等加载图片,由RequestHandler实现对不同图片加载请求类型的支持。Picasso类中存在RequestHandler列表成员对象,构造函数中初始化列表。初始化代码如下:

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);

allRequestHandlers.add(new ResourceRequestHandler(context));
if (extraRequestHandlers != null) {
    allRequestHandlers.addAll(extraRequestHandlers);
}
allRequestHandlers.add(new ContactsPhotoRequestHandler(context));  // 通信录图片
allRequestHandlers.add(new MediaStoreRequestHandler(context));    //MediaStore
allRequestHandlers.add(new ContentStreamRequestHandler(context));  // content provider
allRequestHandlers.add(new AssetRequestHandler(context));   // assert文件夹
allRequestHandlers.add(new FileRequestHandler(context));   // file文件
allRequestHandlers.add(new NetworkRequestHandler(dispatcher.downloader, stats));  //网络图片
requestHandlers = Collections.unmodifiableList(allRequestHandlers);

  RequestHandler通过重写canHandleRequest方法实现对不同类型支持。在NetworkRequestHandler中,调用Downloader的load方法实现网络加载。

Downloader

downloader

  Downloader是实际的网络下载类,当okhttp库存在时,使用okhttp库做网络下载,否则使用HttpURLConnection。

Cache/Stats

  Cache表示图片缓存接口,默认使用LruCache,实现了近期最少使用算法。Stats用于记录缓存情况和计算图片加载情况,包含cacheHits,cacheMisses,totalDownloadSize等属性。

总结

  Picasso是优秀的开源框架,实现了图片加载、变换和缓存操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值