fresco系列一 异步框架的设计与实现

fresco开篇文章介绍到,因为java.util.concurrent包中的future类只有两个结果,在表现图片连续loading的时候能力不足。因此fresco自己实现了一套异步框架。
这篇文章分析下fresco这套异步框架的设计与实现。
代码版本0.10.0

在分析fresco的这套异步框架之前,先看下它的典型使用方法。
fresco中异步框架的一个典型应用就是使用SimpleDraweeView来加载网络图片。
SimpleDraweeView.setImageURI(your-url); —> … //省略一系列大概十几个函数的调用 —> AbstractDraweeController.onAttach —>

AbstractDraweeController.submitRequest()  
mDataSource = getDataSource();               
DataSubscriber<T> subscriber = new BaseDataSubscriber<T>(){...};
mDataSource.subscribe(subscriber,immediateExecutor);

fresco的异步框架和rxjava,agera一样,本质就是观察者模式。
在上述代码中,mDataSource类型为DataSource<T>,是一个数据源,也就是一个被观察者。subscriber是观察者。通过dataSource.subscribe函数,dataSource和subscriber建立了一个订阅关系。就是一旦dataSource产生了一个事件,它就会通知subscriber去处理这个事件。

如图所示,DataSource和DataSubscriber都是接口。
通过它们的接口我们可以合理推测出:
1 DataSource的subscribe函数负责和DataSubscriber建立订阅关系。
2 DataSource的接口getResult,isFinished,hasFailed确立这个接口作为一个数据源应该有的持有一个数据的能力。
3 DataSubscriber作为一个被数据源“通知”的对象,具有响应数据的能力。onNewResult,onFailure。
4 DataSource,DataSubscriber的getProgress,onProgressUpdate使它们具有响应连续变化的能力。—> 比如显示一张图片的loading过程。

写过rxjava的同学看着subscribe函数一定很熟悉,因为这个api和rxjava的api一模一样。
我们比较一下fresco的subscribe和rxjava的subscribe的不同。
如上图所示,rxjava的subscribe函数是“整个异步事件流的发动机”,就是说,只有调用了subscribe函数,整个事件流才开始运作。
而fresco的subscribe函数并不是事件流的发动机,事实上,fresco的事件流在调用mDataSource=getDataSource();的时候就发动了,在调用subscribe的时候如果此时已经拿到结果(比如说命中了本地缓存),那整个事件流就结束了,是一个同步过程。

下面我们看下mDataSource的实现类是哪一个类。
AbstractDraweeController.getDataSource —> …//省略几个中间函数调用 
—> PipelineDraweeControllerBuilder.mImagePipeline.fetchDecodeImage —> 
ImagePipeline.fetchDecodedImage —> CloseableProducerToDataSourceAdapter
  //Pipeline就是流的意思 ImagePipeline就是指对image的流处理。
  //一幅图回忆一下fresco的图片处理流 —> 后面的文章也会做个介绍
因此mDataSource是一个CloseableProducerToDataSourceAdapter的实例。
它的uml图

现在我们来看看这个和rxjava的API一模一样的函数:subscribe的具体实现吧。
mDataSource.subscribe —>
CloseableProducerToDataSourceAdapter.subscribe —>
AbstractDataSource.subscribe(DataSubscriber<T> subscriber,executor)
boolean notify = hasResult()||isFinished()||wasCancelled(); 
if(notify)
  notifyDataSubscriber(subscriber,executor,isFailed,isCancelled);

从这个函数的实现我们看到,函数对是否有结果做了一个判断,如果有结果了就通知subscriber处理结果,然后函数就返回了。
从这里我们确定了两个事实。
1 AbstractDataSource的subscriber一定不是事件流的发起者,因为我们没有看到类似事件流开始的函数调用。
2 AbstractDataSource.subscriber不具备reactive能力,即这个函数是一个同步函数。

如果是同步的情况,DataSource调用subscriber的时候立马就有结果了,也就是立马就响应了。那么异步的情况呢?fresco是怎么使datasource具备异步能力呢?
答案在AbstractDataSource的子类AbstractProducerToDataSourceAdapter的构造函数中。
AbstractProducerToDataSourceAdapter(Producer<T> prducer) 
producer.produceResult(createConsumer(),ctx);

在这个构造函数中我们看到有这么一行代码producer.produceResult(createConsumer(),ctx);
在这里,传入的producer就是image pipeline的一长串处理流(后面的文章会详细介绍),为了简单起见暂且把该producer当成NetworkFetchProducer的一个实例。
NetworkFetchProducer uml 图

从接口上可以看出来Producer具有“产生”一个结果的能力。
我们看看 NetworkFetchProducer是怎么产生一个结果的。
NetworkFetchProducer.produceResults(Consumer<> consumer,ProducerContext ctx)
FetchState state = mNetworkFetcher.createFetchState(consumer,context);
mNetworkFetcher.fetch(fetchState,new NetworkFetcher.Callback(){...});
这里mNetworkFetcher是一个HttpUrlConnectionNetworkFetcher的实例

想必你也猜到了,这不就是我们常见的网络请求嘛,最终一定会调到这个callback回调。
确实如此,fresco在这里构建异步的方式就是,通过“别人”(这里就是http的callback)去通知dataSource,然后dataSource再去通知subscriber来模拟一个reactive能力。

我们看到AbstractDataSource.setResult接口就是暴露给http request的callback的。
这就是fresco在异步情况下进行响应的方法。
其实produceResults中还封装了两个参数。
consumer:producer产生结果就会通知consumer。
producerContext:封装了网络请求的参数,比如说请求的url,请求的id。
为了简单起见,暂时掠过。

整个数据流是这么走的。producer先调用produce results,然后发起了一个http request,http request拿到结果后调用到http request callback,这个callback最终会调用AbstractDataSource的setResult,最终回调用调subscriber的onNewResult函数。

producer.produceResults —> fetcher.callback.onResponse(http request) —> 
producer.onResponse —> consumer.onNewResult —>
AbstractProducerToDataSourceAdapter.createConsumer.onNewResultImpl —>
AbstractDataSource.setResult —>
AbstractDataSource.notifyDataSubscribers —>
AbstractDataSource.subscriber.onNewResult 

上述过程就是fresco构建异步框架方式。
ok,总结一下。
1 DataSource<T>,DataSubscriber<T>是fresco的响应式接口。
2 与rxjava不同的是,DataSource.subscribe不是事件流的发起点。调用subscribe函数的时候,可能已经拿到结果,这时候会立即返回,否则通过producer consumer来通知拿到结果来模拟reactive。
3 producer接口即事件流,也是它的实现类具备开启了事件流的能力。—> 后面有介绍。
4 subscribe的第二个参数executor这里没有介绍。简单说一下,这个executor是拿到结果的executor,而不是事件流运行的executor。它的表现和java.util.concurrent包的future其实差不多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值