Android 源码解析: 图片加载库Picasso 3 核心类

来源:互联网 发布:拉法叶舰案 知乎 编辑:程序博客网 时间:2024/05/21 17:23
Android 源码解析: 图片加载库Picasso 3 核心类

Picasso类库中各个类的设计:
Picasso是Picasso框架的入口,同时也负责初始化各种工作的子线程,工作的实例;RequestCreator则是对任务的描述;而BitmapHunter则是一个具体的工作的线程,接受Picasso中配置好的调度池的调度同时负责知道对应的ReqeustHandler去执行数据请求,并将结果解析为图片,还可以进行一些图片的处理(Transformation),在Picasso当中,任务调度用的类是Dispatcher。
      Picasso的主要流程是:
  1. 初始化Picasso,实例化其唯一的对象。
  2. 根据传入的Url、File、resource Id,构建ReqeustCreator对象
  3. 根据ReqeustCreator构建Request对象,同时根据Reqeust属性,尝试从Cache中访问数据
  4. Cache Hit,则通过回调,设置Target或者ImageView,完成该Reqeust
  5. 如果Cache Miss,那么则构建相应的Action,并提交到DispatcherThread当中。
  6. Dispatcher中的Handler接收到相应的Message,调用dispatcher.performSubmit(action)进行处理。
  7. 创建BitmapHunter对象,并提交到PicassoExecutorService线程池
  8. 再次检查Memory Cache中已经有缓存,如果Hit,则读取缓存中的Bitmap
  9. 如果Cache miss,则交给Action对应的ReqeustHandler进行处理,比如网络请求,或者从File读取图片
  10. 返回结果之后,通知Dispatcher中的Handler处理结果。
  11. DispatcherThread中将BitmapHunter的结果打包(batch),最快200ms打包一次。通知主线程HANDLER进行处理
  12. 主线程HANDLER接收打包的BitmapHunter,对最后的结果进行分发。
  Picasso架构图如下图:图片来自网络



Cache,缓存类

LruCacha,主要是get和set方法,存储的结构采用了LinkedHashMap,这种map内部实现了lru算法(Least Recently Used 近期最少使用算法)。
因为会涉及多线程,所以在存取的时候都会加锁。而且每次set操作后都会判断当前缓存区是否已满,如果满了就清掉最少使用的图形。详见LruCachad的private void trimToSize(int maxSize)方法。

Request,操作封装类


所有对图形的操作都会记录在这里,供之后图形的创建使用,如重新计算大小,旋转角度,也可以自定义变换,只需要实现Transformation,一个bitmap转换的接口。
/** Image transformation. */public interface Transformation {  /**   * Transform the source bitmap into a new bitmap. If you create a new bitmap   * instance, you must call {@link android.graphics.Bitmap#recycle()} on   * {@code source}. You may return the original if no transformation is   * required.   */  Bitmap transform(Bitmap source);  /**   * Returns a unique key for the transformation, used for caching purposes. If   * the transformation has parameters (e.g. size, scale factor, etc) then these   * should be part of the key.   */  String key();}
当操作封装好以后,会将Request传到另一个结构中Action。

Action 类

Action代表了一个具体的加载任务,主要用于图片加载后的结果回调,有两个抽象方法,complete和error,也就是当图片解析为bitmap后用户希望做什么。最简单的就是将bitmap设置给imageview,失败了就将错误通过回调通知到上层。
ImageViewAction实现了Action,在complete中将bitmap和imageview组成了一个PicassoDrawable,里面会实现淡出的动画效果。
有了加载任务,具体的图片下载与解析是在哪里呢?这些都是耗时的操作,应该放在异步线程中进行,就是下面的BitmapHunter。

BitmapHunter类

BitmapHunter是一个Runnable,其中有一个decode的抽象方法,用于子类实现不同类型资源的解析
还有一个hunt()方法,内部调用了requestHandler的load()方法,用于实现具体图片的网络下载。
参见源码:可以看到,在decode生成原始bitmap,之后如果需要,可以使用BitmapHunter提供的transformResult()和applyCustomTransformations()方法进行转换。最后在将最终的结果传递到上层dispatcher.dispatchComplete(this)。

Dispatcher类 任务调度器

在bitmaphunter成功得到bitmap后,就是通过dispatcher将结果传递出去的,当然让bitmaphunter执行也要通过Dispatcher。
Dispatcher内有一个HandlerThread(DispatcherThread extends HandlerThread),所有的请求都会通过这个thread转换,也就是请求也是异步的,这样应该是为了Ui线程更加流畅,同时保证请求的顺序。

首先是外部调用的是dispatchXXX()方法,然后通过handler将请求转换到对应的performXXX()方法。
最后,将通过action得到具体的BitmapHunder,然后交给ExecutorService执行。




0 0