SimpleDraweeView层级初始化

GenericDraweeHierarchyInflater 从xml中解析SimpleDraweeView属性值,(收集属性),然后赋值给GenericDraweeHierarchyBuilder去创建,在GenericDraweeView的构造函数中去build,创建GenericDraweeHierarchy,也就是初始化XML中的属性。这个和代码创建一个效果。类似placeholderImage这些是按照层级放到Drawable[]中,根据这个创建mTopLevelDrawablemTopLevelDrawable中可以做渐变,进度等操作。就是改变Drawable[]中不同的drawable实现的。然后setController时候会设置mTopLevelDrawable先显示。

判断OldController能不能复用是根据DraweeHolder::isControllerValid判断,实际上是mController.getHierarchy() == mHierarchy

PipelineDraweeController是唯一实现的

内存缓存

内存缓存包括已经解码(BitmapMemoryCache)的和未解码的(EncodedMemoryCache)。在源码中表示为MemoryCache,有两个实现类,InstrumentedMemoryCache可以做一些自定义的东西,CountingMemoryCache主要缓存类。缓存的节点是Entry,里面有

1
2
public final K key;
public final CloseableReference<V> valueRef;

使用CountingLruMap来存放数据,其中起作用的是LinkedHashMap<K, V> mMap。很显然是LRU。

文件缓存

会有CONTENT_FILE_EXTENSION = ".cnt";的缓存文件和TEMP_FILE_EXTENSION = ".tmp";临时缓存文件。文件储存主要是DefaultDiskStorage起作用。DiskStorageCache是实现文件缓存的主要类,在maybeEvictFilesInCacheDir也实现了LRU控制缓存。上面还有一层是BufferedDiskCache中的StagingArea mStagingArea,查找的现在这里面查找,找不到通过getAsyncDiskStorageCache中查找。写入的时候会先创建临时文件,然后在endInsert中使用commit完成缓存文件替换,写入。

Pipeline流水线

触发加载图片请求是在进入到AbstractDraweeControlleronAttach,然后 submitRequest();请求图片操作。先去getCachedImage()获取缓存解码图片,根据mCacheKeymMemoryCache中获取,mCacheKey中包含url和对图片的一些设置,例如resize,rotation等,都是从imagerequest中获取的。mMemoryCache是通过mImagePipeline.getBitmapMemoryCache()获得,是通过BitmapCountingMemoryCacheFactory创建的CountingMemoryCache

获取到CloseableReference<CloseableImage>,然后包装成drawable,通过GenericDraweeHierarchy设置给mActualImageWrapper,这个也存在之前的drawable数组中,也就是ACTUAL_IMAGE

层层Producer处理,责任链,每一层存在本层能否直接给Consumer提供数据,不能则将Consumer在本层包装一下交给下一层去获取数据。本层的Consumer做一些缓存数据等操作。

例如BitmapMemoryCacheProducerDecodeProducer就是上下层的关系。首先先在BitmapMemoryCacheProducer

produceResults(
      final Consumer<CloseableReference<CloseableImage>> consumer,
      final ProducerContext producerContext)

方法中寻找解码的图片,如果有,返回给消费解码数据的consumer,如果没有则用本层的wrapConsumer包装一下消费解码图片的消费者传递给下面一层的DecodeProducer,调用DecodeProducerproduceResults方法。同理,DecodeProducer本身不产生数据,他只处理图片的解码,所有把上层传来的consumer再包装一次,传给下面的生产者。例如在磁盘上找到了符合条件的图片,则会走消费这一条路,调用层层的consumer,例如到了DecodeProducerconsumer,会异步去解码,解码成功后再去调用上层的ConsumeronNewResult,内部会调用对应层的onNewResultImpl方法,例如BitmapMemoryCacheProducer中的wrapConsumerDelegatingConsumeronNewResultImpl,这里会在内存中缓存解码的图片了。然后再调用上层的consumer。最上层的Consumer是在AbstractProducerToDataSourceAdaptercreateConsumer创建的。然后通过它的setResult方法通知所有的dataSubscriber,然后在主线程回调dataSubscriber.onNewResult,然后就是使用 mSettableDraweeHierarchy.setImage去给mActualImageWrapper.setDrawable(drawable);这就完成了图片的显示。
整个的producer的顺序是在ProducerSequenceFactory::getDecodedImageProducerSequence的方法里面确立的。

Bitmap在内存的分配

谈谈fresco的bitmap内存分配