Fresco正传(4):DraweeController分析
2015-11-13 14:25
253 查看
前言
一口气写了好多了,先配张美女图,放松下眼睛。言归正传,在总览的文章中就分析过,
DraweeController是控制数据逻辑的核心,数据的请求也会在这部分发出。但是,一口气写下来,估计内容会太多,所以本篇博客只分析
DraweeController的体系结构以及内部方法和介绍一些延伸性的东西。至于,如何发出请求获取图片的,后续博客再分析。
当然还是先给出
DraweeController的继承体系,看看能推测出来一些什么。
DraweeController不用说,肯定是一些抽象共性的东西。而
AbstractDraeeController应该是在抽象的基础上,封装了一些共性操作,这也非常符合现在开发技术:通过接口抽象,并给出抽象的共性操作实现,具体怎么做、做什么交给你。那么
VolleyDraweeController和
PipelineDraweeController就应该是具体使用什么样的方法来做事了。
正文
自上而下的分析类以及类中典型的方法。DraweeController
先分析下类注释,看看能发现什么:DraweeController会被
DraweeView所使用。
DraweeView会转发事件给
DraweeController,而
DraweeController会基于事件控制
DraweeHierarchy顶层视图的切换。
简单几句话描述了
DraweeController身为控制器的核心作用:逻辑处理。
往下看,
onAttach()是不是很眼熟,当
DraweeView包含的层级结构被附加在window上时被调用。
还记得在第二篇分析中,博文最后分析
DrwaeeHolder的
attachController()方法吗?没错,哪里调用的就是这个
onAttach()方法。而且,我们说过在调用
attachController()之所以会有这么多限制条件,肯定是由于这里有重要的逻辑发生。在
onAttach()方法中获取数据源、拿到图片、并最后通过观察者设置实际显示的图片,具体的细节稍后再说。
AbstractDraweeController
在正式分析AbstractDraweeController之前还有个小插曲,那就是
DataSource和
DataSubscriber的关系。
如果你有关心
RxJava那么你一定看过这篇文章:给 Android 开发者的 RxJava 详解,
RxJava是响应式编程的一部分,而响应式编程则充分利用了和扩展了观察者模式,使
RxJava非常强大。
如果你有观察者的基础,那么你一定一眼就明白
DataSource是被观察者,而
DataSubscriber是观察者。在被观察者存储着观察者的数据集合,以用来及时通知事件。
public interface DataSource<T> { /** * 通知订阅者数据源状态的改变 * Subscribe for notifications whenever the state of the DataSource changes. */ void subscribe(DataSubscriber<T> dataSubscriber, Executor executor); }
在来看一下
DataSubscriber都有什么。值得一提的是,
DataSource使用完后,必须要求被安全的关闭。
public interface DataSubscriber<T> { void onNewResult(DataSource<T> dataSource); void onFailure(DataSource<T> dataSource); void onCancellation(DataSource<T> dataSource); void onProgressUpdate(DataSource<T> dataSource); }
所以,就有了
BaseDataSubscriber类,实现了
DataSubscriber接口,并在finally中安全关闭了数据源。 这个类
AbstractDraweeController中会用到。
public abstract class BaseDataSubscriber<T> implements DataSubscriber<T> { @Override public void onNewResult(DataSource<T> dataSource) { try { onNewResultImpl(dataSource); } finally { if (dataSource.isFinished()) { dataSource.close(); } } } // ... protected abstract void onNewResultImpl(DataSource<T> dataSource); protected abstract void onFailureImpl(DataSource<T> dataSource); }
正式开始
AbstractDraweeController的分析。先看看类注释能告诉我们什么:
实现了一些通用的功能,并不涉及具体是怎样抓取图片的。
所有的方法都应该在UI线程调用。
再看看构造方法,在其中调用了
init()方法,主要是做了一些状态的初始化:
取消延时释放
重置启动状态
重新初始化重试、手势、监听器
清除旧的层次结构
重置状态常量
虽然代码很多,但是都可以忽略不计的逻辑,实际上我们也不关心这些。接下来就看看非常重要的
onAttach()方法。
@Override public void onAttach() { Preconditions.checkNotNull(mSettableDraweeHierarchy); mDeferredReleaser.cancelDeferredRelease(this); mIsAttached = true; if (!mIsRequestSubmitted) { submitRequest(); } }
检查
SettableDraweeHierarchy可设置的层次机构不许为NULL,否则直接报异常。是否是请求状态,是就调用
submitRequest()方法发送请求。
从这里开始会完成一些列复杂的操作,先看一张图吧。
protected void submitRequest() { ... mSettableDraweeHierarchy.setProgress(0, true); ... mDataSource = getDataSource(); ... // 此处以第一次请求为例,所以wasImmediate为false final boolean wasImmediate = mDataSource.hasResult(); //------------创建dataSubscriber的匿名内部类,交由AbstractDraweeController处理 final DataSubscriber<T> dataSubscriber = new BaseDataSubscriber<T>() { @Override public void onNewResultImpl(DataSource<T> dataSource) { // isFinished must be obtained before image, otherwise we might set intermediate result // as final image. boolean isFinished = dataSource.isFinished(); float progress = dataSource.getProgress(); T image = dataSource.getResult(); if (image != null) { onNewResultInternal(id, dataSource, image, progress, isFinished, wasImmediate); } else if (isFinished) { onFailureInternal(id, dataSource, new NullPointerException(), /* isFinished */ true); } } @Override public void onFailureImpl(DataSource<T> dataSource) { onFailureInternal(id, dataSource, dataSource.getFailureCause(), /* isFinished */ true); } @Override public void onProgressUpdate(DataSource<T> dataSource) { boolean isFinished = dataSource.isFinished(); float progress = dataSource.getProgress(); onProgressUpdateInternal(id, dataSource, progress, isFinished); } }; // 给数据源注册观察者 mDataSource.subscribe(dataSubscriber, mUiThreadImmediateExecutor); }
整个方法做了如下的事情:
设置加载进度为0
获取数据源,这句话是核心语句。并且
getDataSource()是个抽象方法,交给子类具体处理。
创建数据源观察者,并在内部类的
onNewResultImpl()方法,调用
AbstarctDraweeController的方法
onNewResultInternal()处理数据源获取的结果。
为数据源注册观察者。等待回调的产生。
在
BaseDataSubscriber的
onNewResultImple()方法的逻辑就简单了,看看数据是否加载完毕和加载的进度情况,如果数据源结果不为空就调用
onNewResultInternal()方法进一步处理。
看看
onNewResultInternal()方法做了什么事:
检查是否是自己想要的结果,如果不是,直接释放资源。
如果是想要的数据源,创建对应的drawable。
调用
hierarchy.setImage(draweavke)设置当前显示的draweable。
调用
getControllerListener().onFilalImageSet()回调图像设置成功的结果。
最后在finally中释放之前缓存的drawable对象和Image对象。
private void onNewResultInternal( String id, DataSource<T> dataSource, @Nullable T image, float progress, boolean isFinished, boolean wasImmediate) { // 检查是否是自己想要的结果,如果不是,直接释放资源 .... // 如果是想要的数据源,创建对应的drawable,设置当前显示的drawable,释放之前缓存的drawable对象和Image对象 Drawable drawable = createDrawable(image); ... try { // 设置当前显示的drawable if (isFinished) { mSettableDraweeHierarchy.setImage(drawable, 1f, wasImmediate); // 回调设置图像结束 getControllerListener().onFinalImageSet(id, getImageInfo(image), getAnimatable()); } ... } finally { // 释放之前缓存的drawable对象和Image对象 .... } }
至此,
AbstractDraweeController类的分析就基本结束。
PipelineDraweeController
为什么选择分析PipelineDraweeController?,还记得在Fresco正传(2):DraweeView分析,分析到
Fresco类源码时调用的
initializeDrawee()方法么?
private static void initializeDrawee(Context context) { sDraweeControllerBuilderSupplier = new PipelineDraweeControllerBuilderSupplier(context); SimpleDraweeView.initialize(sDraweeControllerBuilderSupplier); }
这里表明默认使用的Controller是
PipelineDraweeController类
看一下类注释,看看能够了解到什么信息:
DraweeController是ImagePipeline和SettableDraweeHierarchy的桥梁。
实际显示的图像是数据源提供的,而数据源是在
attach和
detach时自动获取和关闭的。
还记得在分析
AbstractDraweeController时提到过的
getDataSource()方法吗?这里有实现,看看是怎么样的:
Override protected DataSource<CloseableReference<CloseableImage>> getDataSource() { return mDataSourceSupplier.get(); }
先上一张图,清醒清醒,看看
getDataSource()是怎么样被调用的。
哈哈。我怎么觉得画的特别棒呢。
想要数据源,则需要数据源提供者提供
mDataSourceSupplier,在
init()方法中,成员变量
mDataSourceSupplier被赋值。
private void init(Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier) { mDataSourceSupplier = dataSourceSupplier; }
init()方法在
PipelineDraweeController的构造方法中调用,在外部传入了
dataSourceSupplier参数。通过
alt+f7看看哪里调用构造方法,发现在
PipilineDraweeControllerFactory工厂中的
newController()方法,构造了
PipelineDraweeController类的实例,并将
newController()的
dataSourceSupplier参数传入了构造方法中。
public PipelineDraweeController newController( Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier, String id, Object callerContext) { // 创建控制器 return new PipelineDraweeController( mResources, mDeferredReleaser, mAnimatedDrawableFactory, mUiThreadExecutor, dataSourceSupplier, id, callerContext); }
再跟踪一下哪里调用了工厂的
newController()方法。发现是
PipelineDraweeControllerBuiler的
obtainController()调用了。更深入的细节,例如:
obtainDataSourceSupplier()先不分析,先把思路捋清楚。
@Override protected PipelineDraweeController obtainController() { DraweeController oldController = getOldController(); PipelineDraweeController controller; // 如果已经有旧的contoller if (oldController instanceof PipelineDraweeController) { controller = (PipelineDraweeController) oldController; controller.initialize( obtainDataSourceSupplier(), generateUniqueControllerId(), getCallerContext()); } else { // 第一次请求 controller = mPipelineDraweeControllerFactory.newController( obtainDataSourceSupplier(), generateUniqueControllerId(), getCallerContext()); } // 返回build 所需的controller return controller; }
在跟踪一下哪里调用了
obtainController()方法,发现是在
buildController()方法中调用的。而又在
AbstractDraweeControllerBuilder的
build()方法中,调用了
buildController()方法。
protected AbstractDraweeController buildController() { AbstractDraweeController controller = obtainController(); // 核心,获取controller // controller.setRetainImageOnFailure(getRetainImageOnFailure()); maybeBuildAndSetRetryManager(controller); maybeAttachListeners(controller); return controller; } @Override public AbstractDraweeController build() { validate(); // if only a low-res request is specified, treat it as a final request. if (mImageRequest == null && mMultiImageRequests == null && mLowResImageRequest != null) { mImageRequest = mLowResImageRequest; mLowResImageRequest = null; } return buildController(); }
最后,是哪里调用的
AbstractDraweeControllerBuilder的
build()方法? 这次你一定很熟悉了,是在
SimpleDraweeView类的
setImageURI()方法中。构建出
DraweeController后,将其交给了
DraweeView的体系。
public void setImageURI(Uri uri, @Nullable Object callerContext) { DraweeController controller = mSimpleDraweeControllerBuilder .setCallerContext(callerContext) .setUri(uri) .setOldController(getController()) .build(); setController(controller); }
最后的问题,
mSimpleDraweeControllerBuiler是哪里来的?相信不用我多说了吧。
这样整个获取数据源的流程,我们就串联起来了。在看一下这个图,是不是更清晰了?
最后
DraweeController的体系分析就基本完成了,如果觉得对您有帮助,多多留言哦。下篇分析是如何发出请求的。
github:https://github.com/biezhihua
Fresco正传(3):DraweeHierarchy分析:http://blog.csdn.net/biezhihua/article/details/49800313
相关文章推荐
- Oracle 使用触发器监控用户操作表
- CAS 单点登录
- Csv-DataTable-Excel格式的相互转换附StopWathch
- [Windows Server 2008] 安装PHP+MySQL方法
- 如何创建一个win32程序
- Retain特质属性在MRC中的陷阱以及ARC中对其的规避
- Air中添加命令行参数的方法
- this class is not key value coding-compliant for the key pstype.'
- ibatis源码分析—配置文件解析(2)
- Redis学习笔记1-Redis安装
- java代码优化性能总结
- [LeetCode]Linked List Cycle II
- PAT 1067. Sort with Swap(0,*)
- [LeetCode]Linked List Cycle II
- JZ006: 捕获到 IO 例外:com.sybase.jdbc3.jdbc.SybConnectionDeadException: JZ0C
- android studio 快捷键
- LIKE,CHARINDEX,IN,EXISTS 效率分析汇总(补充中)
- VS2015中快捷注释代码块
- nopcommerce
- Android整理笔记