4.3.1.2.1 Producer和DataSource之间适配器处理的逻辑

还是从程序的入口开始说吧

CloseableProducerToDataSourceAdapter.create() 源码

此处看到无非是创建了一个新的数据适配器而已CloseableProducerToDataSourceAdapter

  public static <T> DataSource<CloseableReference<T>> create(
Producer<CloseableReference<T>> producer,
SettableProducerContext settableProducerContext,
RequestListener listener) {
return new CloseableProducerToDataSourceAdapter<T>(
producer, settableProducerContext, listener);
}

继续跟踪

CloseableProducerToDataSourceAdapter构造的过程

看到这里,发现并没有做什么特殊的操作,只是调用了父类构造而已

  private CloseableProducerToDataSourceAdapter(
Producer<CloseableReference<T>> producer,
SettableProducerContext settableProducerContext,
RequestListener listener) {
super(producer, settableProducerContext, listener);
}

AbstractProducerToDataSourceAdapter构造的过程

寻找了这么久,终于找到了核心的逻辑,在这里,

  1. 初始化Adapter的参数
  2. 通知外界的mRequestListener已经开始了请求
  3. 生产者producer开始了生产数据(核心逻辑)

    protected AbstractProducerToDataSourceAdapter(

    Producer producer,

    SettableProducerContext settableProducerContext,

    RequestListener requestListener) {

    mSettableProducerContext = settableProducerContext;

    mRequestListener = requestListener;

    mRequestListener.onRequestStart(

    settableProducerContext.getImageRequest(),

    mSettableProducerContext.getCallerContext(),

    mSettableProducerContext.getId(),

    mSettableProducerContext.isPrefetch());

    producer.produceResults(createConsumer(), settableProducerContext);

    }

   其他无关部分,我们先不关心了,直接看看,核心逻辑的操作

  1. 创建了一个消费者
  2. 传递给生产者来生产结果

打开我们的producer.producerResults,发现这只是个接口,这个其实就是面向接口的编程嘛,无论我们的请求需要做什么操作,这里只是通知生产者要开始生产工作了而已.

   前面我们已经提到了网络数据的producer是如何一步一步包装,然后创建的,我们还是以第一次网络请求的数据做参照,但是涉及到的producer也是比较多的,我们就挑选最先处理的producer和最后处理的producer和中间有代表性的一两个producer来做说明

   再来回顾一下,producer的相关过程,网络获取数据的producer会一步步包装,最后包装给BitmapMemoryCacheGetProducer,就是内存获取的producer,因而最终的producer就是BitmapMemoryCacheGetProducer,即这个调用的producer就是我们的BitmapMemoryCacheGetProducer

那么现在就可以从BitmapMemoryCacheGetProducer的produceResult来入手了

BitmapMemoryCacheGetProducer的继承体系

Producer

    --| BitmapMemoryCacheProducer

        --| BitmapMemoryCacheGetProducer

BitmapMemoryCacheGetProducer只是一个负责从内存中获取对应的数据的producer,查看其源码,发现没有复写produceResult方法,那就查看基类的produceResult

BitmapMemoryCacheProducer.produceResults() 源码

从类的名字,便可以知道,这个只是用于内存存取的producer,因而在producerResult的时候,会先从自己的内存中获取一下,查看是否存在于内存中,如果存在,直接获取到通知consumer即可,如果内存中不存在,才会去通知下一个处理器来处理这些事情,下个处理器在处理完成这些数据后,还是会通知消费者即回调的方式,来完成后续的操作,这就是生成处理完成的数据,处理完的结果如何应该保存到内存中呢?肯定是要生成一个key,然后将这个key保存到内存中.

 @Override
public void produceResults(
final Consumer<CloseableReference<CloseableImage>> consumer,
final ProducerContext producerContext) { final ProducerListener listener = producerContext.getListener();
final String requestId = producerContext.getId();
listener.onProducerStart(requestId, getProducerName());
final ImageRequest imageRequest = producerContext.getImageRequest();
final CacheKey cacheKey = mCacheKeyFactory.getBitmapCacheKey(imageRequest); CloseableReference<CloseableImage> cachedReference = mMemoryCache.get(cacheKey); if (cachedReference != null) {
boolean isFinal = cachedReference.get().getQualityInfo().isOfFullQuality();
if (isFinal) {
listener.onProducerFinishWithSuccess(
requestId,
getProducerName(),
listener.requiresExtraMap(requestId) ? ImmutableMap.of(VALUE_FOUND, "true") : null);
consumer.onProgressUpdate(1f);
}
consumer.onNewResult(cachedReference, isFinal);
cachedReference.close();
if (isFinal) {
return;
}
} if (producerContext.getLowestPermittedRequestLevel().getValue() >=
ImageRequest.RequestLevel.BITMAP_MEMORY_CACHE.getValue()) {
listener.onProducerFinishWithSuccess(
requestId,
getProducerName(),
listener.requiresExtraMap(requestId) ? ImmutableMap.of(VALUE_FOUND, "false") : null);
consumer.onNewResult(null, true);
return;
} Consumer<CloseableReference<CloseableImage>> wrappedConsumer = wrapConsumer(consumer, cacheKey);
listener.onProducerFinishWithSuccess(
requestId,
getProducerName(),
listener.requiresExtraMap(requestId) ? ImmutableMap.of(VALUE_FOUND, "false") : null);
mNextProducer.produceResults(wrappedConsumer, producerContext);
}

消费者是如何处理这个回调呢

BitmapMemoryCacheProducer.wrapConsumer() 源码

 protected Consumer<CloseableReference<CloseableImage>> wrapConsumer(
final Consumer<CloseableReference<CloseableImage>> consumer,
final CacheKey cacheKey) {
return new DelegatingConsumer<
CloseableReference<CloseableImage>,
CloseableReference<CloseableImage>>(consumer) {
@Override
public void onNewResultImpl(CloseableReference<CloseableImage> newResult, boolean isLast) {
// ignore invalid intermediate results and forward the null result if last
if (newResult == null) {
if (isLast) {
getConsumer().onNewResult(null, true);
}
return;
}
// stateful results cannot be cached and are just forwarded
if (newResult.get().isStateful()) {
getConsumer().onNewResult(newResult, isLast);
return;
}
// if the intermediate result is not of a better quality than the cached result,
// forward the already cached result and don't cache the new result.
if (!isLast) {
CloseableReference<CloseableImage> currentCachedResult = mMemoryCache.get(cacheKey);
if (currentCachedResult != null) {
try {
QualityInfo newInfo = newResult.get().getQualityInfo();
QualityInfo cachedInfo = currentCachedResult.get().getQualityInfo();
if (cachedInfo.isOfFullQuality() || cachedInfo.getQuality() >= newInfo.getQuality()) {
getConsumer().onNewResult(currentCachedResult, false);
return;
}
} finally {
CloseableReference.closeSafely(currentCachedResult);
}
}
}
// cache and forward the new result
CloseableReference<CloseableImage> newCachedResult =
mMemoryCache.cache(cacheKey, newResult);
try {
if (isLast) {
getConsumer().onProgressUpdate(1f);
}
getConsumer().onNewResult(
(newCachedResult != null) ? newCachedResult : newResult, isLast);
} finally {
CloseableReference.closeSafely(newCachedResult);
}
}
};
}

在这里用到了代理设计模式,因为呢,每个producer都会调用consumer的方法,但是不同的producer需要在原有consumer的基础上处理自己的一些逻辑,这里呢?就需要将原来的consumer进行代理,调用时,先处理自己的逻辑,然后调用原有consumer的相关方法即可.

这里我们看到消费者是在产生新的结果时会缓存这个结果,但是这个只是基类BitmapMemoryCacheProducer的wrapConsumer的方法,我们这个实现类BitmapMemoryCacheGetProducer只是用于内存获取而已,所以,不会涉及到内存缓存这块,只是获取,所以BitmapMemoryCacheGetProducer的wrapConsumer只是返回方法中的consumer.

看完了这个内存缓存的producer后,我们再看看最后的producer,即网络数据获取的相关producer:NetworkFetchProducer

Fresco 源码分析(三) Fresco服务端处理(3) DataSource到Producer的适配器逻辑以及BitmapMemoryCacheProducer处理的逻辑的更多相关文章

  1. Fresco 源码分析(三) Fresco服务端处理(1) ImagePipeline为何物

    4.3 服务端的处理 备注: 因为是分析,而不是设计,所以很多知识我们类似于插叙的方式叙述,就是用到了哪个知识点,我们再提及相关的知识点,如果分析到了最后,我想想是不是应该将这个架构按照设计的方式,重 ...

  2. Fresco 源码分析(三) Fresco服务端处理(2) Producer具体实现的内容

    我们以mProducerFactory.newNetworkFetchProducer()为例,因为这些创建新的producer的方式类似,区别在于是否有包装的处理器,即如果当前处理器中没有正在处理的 ...

  3. Fresco 源码分析(二) Fresco客户端与服务端交互(3) 前后台打通

    4.2.1.2.4 PipelineDraweeControllerBuilder.obtainController()源码分析 续 上节中我们提到两个核心的步骤 obtainDataSourceSu ...

  4. Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题

    4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...

  5. Fresco 源码分析(二) Fresco客户端与服务端交互(2) Fresco.initializeDrawee()分析 续

    4.2.1.2 Fresco.initializeDrawee()的过程 续 继续上篇博客的分析Fresco.initializeDrawee() sDraweeControllerBuilderSu ...

  6. 【Netty源码分析】Netty服务端bind端口过程

    这一篇博客我们介绍一下Netty服务端绑定端口的过程,我们通过跟踪代码一直到NIO原生绑定端口的操作. 绑定端口操作 ChannelFuture future = serverBootstrap.bi ...

  7. Fresco 源码分析(一) DraweeView-DraweeHierarchy-DraweeController(MVC) DraweeHierachy+DraweeController的分析

    4.1.5.2 模型层DraweeHierachy继承体系以及各个类的作用 DraweeHierachy (I) --| SettableDraweeHierarchy (I) ------| Gen ...

  8. 使用react全家桶制作博客后台管理系统 网站PWA升级 移动端常见问题处理 循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi [Abp 源码分析]四、模块配置 [Abp 源码分析]三、依赖注入

    使用react全家桶制作博客后台管理系统   前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基 ...

  9. angular源码分析:$compile服务——directive他妈

    一.directive的注册 1.我们知道,我们可以通过类似下面的代码定义一个指令(directive). var myModule = angular.module(...); myModule.d ...

随机推荐

  1. Spring+Struts2+Mybatis框架搭建时的常见典型问题

    搭建SSM框架时,总是遇到这样那样的问题,有的一眼就能看出来,有的需要经验的积累.现将自己搭建SSM框架时遇到的典型问题总结如下: 一.Struts2框架下的action中无法使用@Autowired ...

  2. 解决IE apk变成zip:Android 手机应用程序文件下载服务器Nginx+Tomcat配置解决方法

    APK文件其实是zip格式,但后缀名被修改为apk,通过UnZip解压后,可以看到Dex文件,Dex是Dalvik VM executes的全称,即Android Dalvik执行程序,并非Java ...

  3. hdu 1013 Digital Roots

    #include <stdio.h> int main(void) { int m,i;char n[10000]; while(scanf("%s",&n)= ...

  4. Python socket编程之四:模拟分时图

    建立 socket,先运行服务器,再运行客户端,建立连接后服务器从本地数据库调数据一截一截地发送给客户端,客户端接受数据绘图模拟分时图 1.socket # -*- coding: utf-8 -*- ...

  5. Max批量导出工具

    Max批量导出工具 http://www.paulneale.com/scripts/batchItMax/batchItMax.htm Scripts Batch It Max: Batch It ...

  6. windows中快速停掉占用某端口的进程的方法

    在Windows操作系统中,我们在启动一个tomcat服务器时,经常会发现8080端口已经被占用的错误,而我们又不知道如何停止这个tomcat服务器. 本文将通过命令来强行终止这个已经运行的tomca ...

  7. 关于FlexPaper 2.1.2版本 二次开发 Logo 、打印、搜索、缩略图、添加按钮、js交互、右键菜单、书签等相关问题

    2015-03-02 更新文章,由于需求修改,更改了flexpaper插件,故增加第9.10.11小节,下载代码时请注意. 先废话几句.最近用到文档在线浏览功能,之前用的是print2flash(一个 ...

  8. RedHat linux配置yum本地资源

    今天安装个linux平台的oracle数据库,在oracle检测的时候发现有些系统补丁包没有安装,手动rpm安装报有些关联包也没有安装,想想如果一个一个rpm的话累死人了要,所以想起用yum来进行安装 ...

  9. SecureCRT光标颜色

    SecureCRT连linux光标一直没有,尤其是在vim编辑文档的时候特别麻烦,今天找出解决办法: 选项->会话选项->仿真:将ANSI颜色选中: 选项->会话选项->外观: ...

  10. excel插入当前时间快捷键Ctrl+;

    之前写了一篇editplus如何插入当前时间_Ctrl+D的文章,有的同学说excel用习惯了,那在这我们就说一下excel插入当前时间快捷键,让您在excel快速插入当前时间 excel插入当前时间 ...