先看Imagepipeline:
Image pipeline 负责完成加载图像,变成Android设备可呈现的形式所要做的每个事情。
大致流程如下:
- 检查内存缓存,如有,返回
- 后台线程开始后续工作
- 检查是否在未解码内存缓存中。如有,解码,变换,返回,然后缓存到内存缓存中。
- 检查是否在磁盘缓存中,如果有,变换,返回。缓存到未解码缓存和内存缓存中。
- 从网络或者本地加载。加载完成后,解码,变换,返回。存到各个缓存中。
总之你认为是个策略工厂
package com.facebook.imagepipeline.core;
import *
/**
* The entry point for the image pipeline.
*/
@ThreadSafe
public class ImagePipeline {
private static final CancellationException PREFETCH_EXCEPTION =
new CancellationException("Prefetching is not enabled");
private final ProducerSequenceFactory mProducerSequenceFactory;
private final RequestListener mRequestListener;
private final Supplier mIsPrefetchEnabledSupplier;
private final MemoryCache mBitmapMemoryCache;
private final MemoryCache mEncodedMemoryCache;
private final BufferedDiskCache mMainBufferedDiskCache;
private final BufferedDiskCache mSmallImageBufferedDiskCache;
private final CacheKeyFactory mCacheKeyFactory;
private final ThreadHandoffProducerQueue mThreadHandoffProducerQueue;
private AtomicLong mIdCounter;
public ImagePipeline(
ProducerSequenceFactory producerSequenceFactory, // 消费和生产者模式,这个会创建网络请求片段序列
Set requestListeners, // 这货就是最后,下载完图片,通过消费者,最后回掉用的接口
Supplier isPrefetchEnabledSupplier,
MemoryCache bitmapMemoryCache, // 缓存1级
MemoryCache encodedMemoryCache, // 缓存2级
BufferedDiskCache mainBufferedDiskCache, // Frescon 支持大图和小图区别对待,分开buff和toDisk,默认都是这个
BufferedDiskCache smallImageBufferedDiskCache,// 小图
CacheKeyFactory cacheKeyFactory, // 默认的key-value工厂
ThreadHandoffProducerQueue threadHandoffProducerQueue) { // 生产者队列,用于在pause关闭资源
mIdCounter = new AtomicLong(); // 为这个ImagePiple打一个独特内存id
mProducerSequenceFactory = producerSequenceFactory;
mRequestListener = new ForwardingRequestListener(requestListeners);// 这个是回掉接口包装
mIsPrefetchEnabledSupplier = isPrefetchEnabledSupplier;
mBitmapMemoryCache = bitmapMemoryCache;
mEncodedMemoryCache = encodedMemoryCache;
mMainBufferedDiskCache = mainBufferedDiskCache;
mSmallImageBufferedDiskCache = smallImageBufferedDiskCache;
mCacheKeyFactory = cacheKeyFactory;
mThreadHandoffProducerQueue = threadHandoffProducerQueue;
}
private String generateUniqueFutureId() {
return String.valueOf(mIdCounter.getAndIncrement());
}
/**
* Returns a DataSource supplier that will on get submit the request for execution and return a
* DataSource representing the pending results of the task.
* 完成request,带bitmapCacheOnly这个flag策略,加载图片来源
*/
public Supplier>> getDataSourceSupplier(
final ImageRequest imageRequest,
final Object callerContext,
final boolean bitmapCacheOnly) {
return new Supplier>>() {
@Override
public DataSource> get() {
if (bitmapCacheOnly) {
return fetchImageFromBitmapCache(imageRequest, callerContext);
} else {
return fetchDecodedImage(imageRequest, callerContext);
}
}
};
}
/**
* Returns a DataSource supplier that will on get submit the request for execution and return a
* DataSource representing the pending results of the task.
* 完成request,加载图片来源,磁盘或者网络
*/
public Supplier>>
getEncodedImageDataSourceSupplier(
final ImageRequest imageRequest,
final Object callerContext) {
return new Supplier>>() {
@Override
public DataSource> get() {
return fetchEncodedImage(imageRequest, callerContext);
}
};
}
/**
* Submits a request for bitmap cache lookup.
* 完成request,加载图片来源 图片缓存
*/
public DataSource> fetchImageFromBitmapCache(
ImageRequest imageRequest,
Object callerContext) {
try {
Producer> producerSequence =
mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest);
return submitFetchRequest(
producerSequence,
imageRequest,
ImageRequest.RequestLevel.BITMAP_MEMORY_CACHE, // BITMAP_MEMORY_CACHE(4); 这个等级是Bitmap caching
callerContext);
} catch (Exception exception) {
return DataSources.immediateFailedDataSource(exception);
}
}
/**
* Submits a request for execution and returns a DataSource representing the pending decoded
* image(s). 完成request,加载图片来源网络或者磁盘
* The returned DataSource must be closed once the client has finished with it.
*/
public DataSource> fetchDecodedImage(
ImageRequest imageRequest,
Object callerContext) {
try {
Producer> producerSequence =
mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest);
return submitFetchRequest(
producerSequence,
imageRequest,
ImageRequest.RequestLevel.FULL_FETCH, // 这个等级 Fetch (from the network or local storage)
callerContext);
} catch (Exception exception) {
return DataSources.immediateFailedDataSource(exception);
}
}
/**
* Submits a request for execution and returns a DataSource representing the pending encoded
* image(s).
* 最终要调这个Submits
*/
public DataSource> fetchEncodedImage(
ImageRequest imageRequest,
Object callerContext) {
Preconditions.checkNotNull(imageRequest.getSourceUri());
try {
Producer> producerSequence =
mProducerSequenceFactory.getEncodedImageProducerSequence(imageRequest); // 这个很重要了,NetWork请求client在这个里面准备好
// The resize options are used to determine whether images are going to be downsampled during
// decode or not. For the case where the image has to be downsampled and it's a local image it
// will be kept as a FileInputStream until decoding instead of reading it in memory. Since
// this method returns an encoded image, it should always be read into memory. Therefore, the
// resize options are ignored to avoid treating the image as if it was to be downsampled
// during decode.
if (imageRequest.getResizeOptions() != null) {
imageRequest = ImageRequestBuilder.fromRequest(imageRequest)
.setResizeOptions(null)
.build();
}
return submitFetchRequest(
producerSequence,
imageRequest,
ImageRequest.RequestLevel.FULL_FETCH,
callerContext); // 执行生产者消费者 从这里开始了
} catch (Exception exception) {
return DataSources.immediateFailedDataSource(exception);
}
}
public DataSource prefetchToBitmapCache(
ImageRequest imageRequest,
Object callerContext) {
if (!mIsPrefetchEnabledSupplier.get()) {
return DataSources.immediateFailedDataSource(PREFETCH_EXCEPTION);
}
try {
Producer producerSequence =
mProducerSequenceFactory.getDecodedImagePrefetchProducerSequence(imageRequest);
return submitPrefetchRequest(
producerSequence,
imageRequest,
ImageRequest.RequestLevel.FULL_FETCH,
callerContext,
Priority.MEDIUM);
} catch (Exception exception) {
return DataSources.immediateFailedDataSource(exception);
}
}
public DataSource prefetchToDiskCache(
ImageRequest imageRequest,
Object callerContext,
Priority priority) {
if (!mIsPrefetchEnabledSupplier.get()) {
return DataSources.immediateFailedDataSource(PREFETCH_EXCEPTION);
}
try {
Producer producerSequence =
mProducerSequenceFactory.getEncodedImagePrefetchProducerSequence(imageRequest);
return submitPrefetchRequest(
producerSequence,
imageRequest,
ImageRequest.RequestLevel.FULL_FETCH,
callerContext,
priority);
} catch (Exception exception) {
return DataSources.immediateFailedDataSource(exception);
}
}
.........
private DataSource> submitFetchRequest(
Producer> producerSequence,
ImageRequest imageRequest,
ImageRequest.RequestLevel lowestPermittedRequestLevelOnSubmit,
Object callerContext) {
try {
ImageRequest.RequestLevel lowestPermittedRequestLevel =
ImageRequest.RequestLevel.getMax(
imageRequest.getLowestPermittedRequestLevel(),
lowestPermittedRequestLevelOnSubmit);
SettableProducerContext settableProducerContext = new SettableProducerContext(// 创建一个上下文对象,如同Android:Context
imageRequest,
generateUniqueFutureId(),
mRequestListener,
callerContext,
lowestPermittedRequestLevel,
/* isPrefetch */ false,
imageRequest.getProgressiveRenderingEnabled() ||
!UriUtil.isNetworkUri(imageRequest.getSourceUri()),
imageRequest.getPriority());
return CloseableProducerToDataSourceAdapter.create( //生产者数据源开始
producerSequence,
settableProducerContext,
mRequestListener);
} catch (Exception exception) {
return DataSources.immediateFailedDataSource(exception);
}
}
private DataSource submitPrefetchRequest( // 这个就是从内存拿策略和上面差不多,介绍上面那个,不同就是生产者不同
Producer producerSequence,
ImageRequest imageRequest,
ImageRequest.RequestLevel lowestPermittedRequestLevelOnSubmit,
Object callerContext,
Priority priority) {
try {
ImageRequest.RequestLevel lowestPermittedRequestLevel =
ImageRequest.RequestLevel.getMax(
imageRequest.getLowestPermittedRequestLevel(),
lowestPermittedRequestLevelOnSubmit);
SettableProducerContext settableProducerContext = new SettableProducerContext(
imageRequest,
generateUniqueFutureId(),
mRequestListener,
callerContext,
lowestPermittedRequestLevel,
/* isPrefetch */ true,
/* isIntermediateResultExpected */ false,
priority);
return ProducerToDataSourceAdapter.create(
producerSequence,
settableProducerContext,
mRequestListener);
} catch (Exception exception) {
return DataSources.immediateFailedDataSource(exception);
}
}
........
public void pause() {
mThreadHandoffProducerQueue.startQueueing();
}
public void resume() {
mThreadHandoffProducerQueue.stopQueuing();
}
public boolean isPaused() {
return mThreadHandoffProducerQueue.isQueueing();
}
/**
* @return The CacheKeyFactory implementation used by ImagePipeline
*/
public CacheKeyFactory getCacheKeyFactory() {
return mCacheKeyFactory;
}
}
在构造函数中我们看到了mRequestListener = new ForwardingRequestListener(requestListeners);这货就是提交给ImagePipleDraweeController中Listener,基本无用,默认requestListeners为null
流程:
AbstractDraweeController:sumbit() ===>PipelineDraweeController:getDataSource() ===> PipelineDraweeControllerBuilderSupplier === > ImagePipelineFactory === > ImagePipeline ===> ImagePipeline:getDataSourceSupplier() === >fetchDecodedImage() ===>ProducerSequenceFactory:getDecodedImageProducerSequence(imageRequest)处理,然后创建生产者和消费者CloseableProducerToDataSourceAdapter:create() ===>线程等级为ProducerSequenceFactory.BackGroudTask执行request
在介绍生产者之前,先把ProducerSequenceFactory这个看了
public Producer> getDecodedImageProducerSequence(
ImageRequest imageRequest) {
Producer> pipelineSequence =
getBasicDecodedImageSequence(imageRequest);// 这里开始装配
if (imageRequest.getPostprocessor() != null) {// 判断是否有后后处理器,默认是没有
return getPostprocessorSequence(pipelineSequence);
} else {
return pipelineSequence;
}
}
关于后处理器: 完成特殊定制,就是你在下载完成后,这个图片需要特殊要求和处理
Producer> pipelineSequence = getBasicDecodedImageSequence(imageRequest);
private Producer> getBasicDecodedImageSequence(
ImageRequest imageRequest) {
Preconditions.checkNotNull(imageRequest);
Uri uri = imageRequest.getSourceUri(); // setUrl时候构造
Preconditions.checkNotNull(uri, "Uri is null.");
if (UriUtil.isNetworkUri(uri)) {
return getNetworkFetchSequence(); // 网络请求走这个
} else if (UriUtil.isLocalFileUri(uri)) {
if (MediaUtils.isVideo(MediaUtils.extractMime(uri.getPath()))) {
return getLocalVideoFileFetchSequence();
} else {
return getLocalImageFileFetchSequence();
}
} else if (UriUtil.isLocalContentUri(uri)) {
return getLocalContentUriFetchSequence();
} else if (UriUtil.isLocalAssetUri(uri)) {
return getLocalAssetFetchSequence();
} else if (UriUtil.isLocalResourceUri(uri)) {
return getLocalResourceFetchSequence();
} else if (UriUtil.isDataUri(uri)) {
return getDataFetchSequence();
} else {
String uriString = uri.toString();
if (uriString.length() > 30) {
uriString = uriString.substring(0, 30) + "...";
}
throw new RuntimeException("Unsupported uri scheme! Uri is: " + uriString);
}
}
其中大部分我们不关心,先找到核心请求,其它只是策略
getNetworkFetchSequence(); 不用看,就这货了。
/**
* swallow result if prefetch -> bitmap cache get ->
* background thread hand-off -> multiplex -> bitmap cache -> decode -> multiplex ->
* encoded cache -> disk cache -> (webp transcode) -> network fetch.
* 大致就是说,没有缓存你就走disk,再没有就network, multiplex是指多个request load 一起来,一样的流程,因为是有multiplex,所有同步方法
*/
private synchronized Producer> getNetworkFetchSequence() {
if (mNetworkFetchSequence == null) {
mNetworkFetchSequence =
newBitmapCacheGetToDecodeSequence(getCommonNetworkFetchToEncodedMemorySequence());
}
return mNetworkFetchSequence;
}
getCommonNetworkFetchToEncodedMemorySequence() 名字已经暴露你了,什么XXX网络片段请求
/**
* multiplex -> encoded cache -> disk cache -> (webp transcode) -> network fetch.
*/
private synchronized Producer getCommonNetworkFetchToEncodedMemorySequence() {
if (mCommonNetworkFetchToEncodedMemorySequence == null) {
Producer inputProducer =
newEncodedCacheMultiplexToTranscodeSequence(
mProducerFactory.newNetworkFetchProducer(mNetworkFetcher));
mCommonNetworkFetchToEncodedMemorySequence =
ProducerFactory.newAddImageTransformMetaDataProducer(inputProducer);
if (mResizeAndRotateEnabledForNetwork && !mDownsampleEnabled) {
mCommonNetworkFetchToEncodedMemorySequence =
mProducerFactory.newResizeAndRotateProducer(
mCommonNetworkFetchToEncodedMemorySequence);
}
}
return mCommonNetworkFetchToEncodedMemorySequence;
}
看重点,其它乱78遭,旋转改变大小又重新干一个请求,这个不看。
mNetworkFetcher这货是真正底层网络代码了,默认使用HttpUrlConnectionNetworkFetcher,HttpUrlConnection的bug已经在4.3以后修复了,如果要定制okhttp,像作者一样OkHttpNetworkFetcher,需要在Frescon初始化的时候注入:com.facebook.drawee.backends.pipeline.Fresco.initialize(this, OkHttpImagePipelineConfigFactory.newBuilder(this, new okhttp3.OkHttpClient()).build());
ProducerFactory.newAddImageTransformMetaDataProducer(inputProducer); 这货就是消费者添加图片
public static AddImageTransformMetaDataProducer newAddImageTransformMetaDataProducer(
Producer inputProducer) {
return new AddImageTransformMetaDataProducer(inputProducer);
}
/**
* Add image transform meta data producer
*
* Extracts meta data from the results passed down from the next producer, and adds it to the
* result that it returns to the consumer.
*/
public class AddImageTransformMetaDataProducer implements Producer {
private final Producer mInputProducer;
public AddImageTransformMetaDataProducer(Producer inputProducer) {
mInputProducer = inputProducer;
}
@Override
public void produceResults(Consumer consumer, ProducerContext context) {
mInputProducer.produceResults(new AddImageTransformMetaDataConsumer(consumer), context);
}
private static class AddImageTransformMetaDataConsumer extends DelegatingConsumer<
EncodedImage, EncodedImage> {
private AddImageTransformMetaDataConsumer(Consumer consumer) {
super(consumer);
}
@Override
protected void onNewResultImpl(EncodedImage newResult, boolean isLast) {
if (newResult == null) {
getConsumer().onNewResult(null, isLast);
return;
}
if (!EncodedImage.isMetaDataAvailable(newResult)) {
newResult.parseMetaData();
}
getConsumer().onNewResult(newResult, isLast);
}
}
}
基本下载类
// 基本下载类,没有什么特点
/**
* Network fetcher that uses the simplest Android stack.
*
* Apps requiring more sophisticated networking should implement their own
* {@link NetworkFetcher}.
*/
public class HttpUrlConnectionNetworkFetcher extends BaseNetworkFetcher {
private final ExecutorService mExecutorService;
public HttpUrlConnectionNetworkFetcher() {
this(Executors.newFixedThreadPool(NUM_NETWORK_THREADS));
}
@VisibleForTesting
HttpUrlConnectionNetworkFetcher(ExecutorService executorService) {
mExecutorService = executorService;
}
@Override
public FetchState createFetchState(Consumer consumer, ProducerContext context) {
return new FetchState(consumer, context);
}
@Override
public void fetch(final FetchState fetchState, final Callback callback) {
final Future> future = mExecutorService.submit(
new Runnable() {
@Override
public void run() {
fetchSync(fetchState, callback);
}
});
fetchState.getContext().addCallbacks(
new BaseProducerContextCallbacks() {
@Override
public void onCancellationRequested() {
if (future.cancel(false)) {
callback.onCancellation();
}
}
});
}
@VisibleForTesting
void fetchSync(FetchState fetchState, Callback callback) {
HttpURLConnection connection = null;
try {
connection = downloadFrom(fetchState.getUri(), MAX_REDIRECTS);
if (connection != null) {
callback.onResponse(connection.getInputStream(), -1);
}
} catch (IOException e) {
callback.onFailure(e);
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
private HttpURLConnection downloadFrom(Uri uri, int maxRedirects) throws IOException {
HttpURLConnection connection = openConnectionTo(uri);
int responseCode = connection.getResponseCode();
if (isHttpSuccess(responseCode)) {
return connection;
} else if (isHttpRedirect(responseCode)) {
String nextUriString = connection.getHeaderField("Location");
connection.disconnect();
Uri nextUri = (nextUriString == null) ? null : Uri.parse(nextUriString);
String originalScheme = uri.getScheme();
if (maxRedirects > 0 && nextUri != null && !nextUri.getScheme().equals(originalScheme)) {
return downloadFrom(nextUri, maxRedirects - 1);
} else {
String message = maxRedirects == 0
? error("URL %s follows too many redirects", uri.toString())
: error("URL %s returned %d without a valid redirect", uri.toString(), responseCode);
throw new IOException(message);
}
} else {
connection.disconnect();
throw new IOException(String
.format("Image URL %s returned HTTP code %d", uri.toString(), responseCode));
}
}
@VisibleForTesting
static HttpURLConnection openConnectionTo(Uri uri) throws IOException {
URL url = new URL(uri.toString());
return (HttpURLConnection) url.openConnection();
}
......
OkHttp下载介绍
// 下面是OkHttp,使用了异步请求call.enqueue()...不知道童鞋,可以去百度下OkHttp,不难,也是建造者模式
public class OkHttpNetworkFetcher extends
BaseNetworkFetcher {
public static class OkHttpNetworkFetchState extends FetchState {
public OkHttpNetworkFetchState(
Consumer consumer,
ProducerContext producerContext) {
super(consumer, producerContext);
}
}
private final OkHttpClient mOkHttpClient;
private Executor mCancellationExecutor;
/**
* @param okHttpClient client to use
*/
public OkHttpNetworkFetcher(OkHttpClient okHttpClient) {
mOkHttpClient = okHttpClient;
mCancellationExecutor = okHttpClient.dispatcher().executorService();
}
@Override
public OkHttpNetworkFetchState createFetchState(
Consumer consumer,
ProducerContext context) {
return new OkHttpNetworkFetchState(consumer, context);
}
@Override
public void fetch(final OkHttpNetworkFetchState fetchState, final Callback callback) {
fetchState.submitTime = SystemClock.elapsedRealtime();
final Uri uri = fetchState.getUri();
final Request request = new Request.Builder()
.cacheControl(new CacheControl.Builder().noStore().build())
.url(uri.toString())
.get()
.build();
final Call call = mOkHttpClient.newCall(request);
fetchState.getContext().addCallbacks(
new BaseProducerContextCallbacks() {
@Override
public void onCancellationRequested() {
if (Looper.myLooper() != Looper.getMainLooper()) {
call.cancel();
} else {
mCancellationExecutor.execute(new Runnable() {
@Override public void run() {
call.cancel();
}
});
}
}
});
call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(Call call, Response response) throws IOException {
fetchState.responseTime = SystemClock.elapsedRealtime();
final ResponseBody body = response.body();
try {
if (!response.isSuccessful()) {
handleException(
call,
new IOException("Unexpected HTTP code " + response),
callback);
return;
}
long contentLength = body.contentLength();
if (contentLength < 0) {
contentLength = 0;
}
callback.onResponse(body.byteStream(), (int) contentLength);
} catch (Exception e) {
handleException(call, e, callback);
} finally {
try {
body.close();
} catch (Exception e) {
FLog.w(TAG, "Exception when closing response body", e);
}
}
}
@Override
public void onFailure(Call call, IOException e) {
handleException(call, e, callback);
}
});
}
}
}
newBitmapCacheGetToDecodeSequence这货干缓存,前面干网络请求。
/**
* Same as {@code newBitmapCacheGetToBitmapCacheSequence} but with an extra DecodeProducer.
* @param inputProducer producer providing the input to the decode
* @return bitmap cache get to decode sequence
*/
private Producer> newBitmapCacheGetToDecodeSequence(
Producer inputProducer) {
DecodeProducer decodeProducer = mProducerFactory.newDecodeProducer(inputProducer);
return newBitmapCacheGetToBitmapCacheSequence(decodeProducer);
}
DecodeProducer这货images的包装器,build模式
/**
* Decodes images.
*
* Progressive JPEGs are decoded progressively as new data arrives.
*/
public class DecodeProducer implements Producer> {
public static final String PRODUCER_NAME = "DecodeProducer";
// keys for extra map
private static final String BITMAP_SIZE_KEY = "bitmapSize";
private static final String HAS_GOOD_QUALITY_KEY = "hasGoodQuality";
private static final String IMAGE_TYPE_KEY = "imageType";
private static final String IS_FINAL_KEY = "isFinal";
private final ByteArrayPool mByteArrayPool;
private final Executor mExecutor;
private final ImageDecoder mImageDecoder;
private final ProgressiveJpegConfig mProgressiveJpegConfig;
private final Producer mInputProducer;
private final boolean mDownsampleEnabled;
private final boolean mDownsampleEnabledForNetwork;
........
}
里面有执行器和byte数据池,Decoder
回归主线:
newBitmapCacheGetToBitmapCacheSequence(decodeProducer);
/**
* Bitmap cache get -> thread hand off -> multiplex -> bitmap cache
* @param inputProducer producer providing the input to the bitmap cache
* @return bitmap cache get to bitmap cache sequence
*/
private Producer> newBitmapCacheGetToBitmapCacheSequence(
Producer> inputProducer) {
BitmapMemoryCacheProducer bitmapMemoryCacheProducer =
mProducerFactory.newBitmapMemoryCacheProducer(inputProducer);
BitmapMemoryCacheKeyMultiplexProducer bitmapKeyMultiplexProducer =
mProducerFactory.newBitmapMemoryCacheKeyMultiplexProducer(bitmapMemoryCacheProducer);
ThreadHandoffProducer> threadHandoffProducer =
mProducerFactory.newBackgroundThreadHandoffProducer(
bitmapKeyMultiplexProducer,
mThreadHandoffProducerQueue);
return mProducerFactory.newBitmapMemoryCacheGetProducer(threadHandoffProducer);
}
mProducerFactory.newBackgroundThreadHandoffProducer(bitmapKeyMultiplexProducer,mThreadHandoffProducerQueue);还记得前面有说ImagePipeline:mThreadHandoffProducerQueue么,这货维护请求资源,pause开打进行释放,resume反之
mProducerFactory.newBitmapMemoryCacheGetProducer(threadHandoffProducer);
public BitmapMemoryCacheGetProducer newBitmapMemoryCacheGetProducer(
Producer> inputProducer) {
return new BitmapMemoryCacheGetProducer(mBitmapMemoryCache, mCacheKeyFactory, inputProducer);
}
最后塞到Cache中处理
/**
* Bitmap memory cache producer that is read-only.
*/
public class BitmapMemoryCacheGetProducer extends BitmapMemoryCacheProducer {
@VisibleForTesting static final String PRODUCER_NAME = "BitmapMemoryCacheGetProducer";
public BitmapMemoryCacheGetProducer(
MemoryCache memoryCache,
CacheKeyFactory cacheKeyFactory,
Producer> inputProducer) {
super(memoryCache, cacheKeyFactory, inputProducer);
}
@Override
protected Consumer> wrapConsumer(
final Consumer> consumer,
final CacheKey cacheKey) {
// since this cache is read-only, we can pass our consumer directly to the next producer
return consumer;
}
@Override
protected String getProducerName() {
return PRODUCER_NAME;
}
消费者回掉在基类
/**
* Memory cache producer for the bitmap memory cache.
*/
public class BitmapMemoryCacheProducer implements Producer> {
@VisibleForTesting static final String PRODUCER_NAME = "BitmapMemoryCacheProducer";
@VisibleForTesting static final String VALUE_FOUND = "cached_value_found";
private final MemoryCache mMemoryCache;
private final CacheKeyFactory mCacheKeyFactory;
private final Producer> mInputProducer;
public BitmapMemoryCacheProducer(
MemoryCache memoryCache,
CacheKeyFactory cacheKeyFactory,
Producer> inputProducer) {
mMemoryCache = memoryCache;
mCacheKeyFactory = cacheKeyFactory;
mInputProducer = inputProducer;
}
@Override
public void produceResults(
final Consumer> consumer,
final ProducerContext producerContext) {
final ProducerListener listener = producerContext.getListener();
final String requestId = producerContext.getId();
listener.onProducerStart(requestId, getProducerName());
final ImageRequest imageRequest = producerContext.getImageRequest();
final Object callerContext = producerContext.getCallerContext();
final CacheKey cacheKey = mCacheKeyFactory.getBitmapCacheKey(imageRequest, callerContext);
CloseableReference 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> wrappedConsumer = wrapConsumer(consumer, cacheKey);
listener.onProducerFinishWithSuccess(
requestId,
getProducerName(),
listener.requiresExtraMap(requestId) ? ImmutableMap.of(VALUE_FOUND, "false") : null);
mInputProducer.produceResults(wrappedConsumer, producerContext);
}
protected Consumer> wrapConsumer(
final Consumer> consumer,
final CacheKey cacheKey) {
return new DelegatingConsumer<
CloseableReference,
CloseableReference>(consumer) {
@Override
public void onNewResultImpl(CloseableReference 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 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 newCachedResult =
mMemoryCache.cache(cacheKey, newResult);
try {
if (isLast) {
getConsumer().onProgressUpdate(1f);
}
getConsumer().onNewResult(
(newCachedResult != null) ? newCachedResult : newResult, isLast);
} finally {
CloseableReference.closeSafely(newCachedResult);
}
}
};
}
protected String getProducerName() {
return PRODUCER_NAME;
}
}
produceResults()来自AbstractProducerToDataSourceAdapter(),往上追踪这个方法来自ImagePipleine:submitFetchRequest():CloseableProducerToDataSourceAdapter:creat()进行回掉
然后函数结尾的时候走mInputProducer.produceResults(wrappedConsumer, producerContext);
mInputProducer来自ImagePiple:fetchDecodedImage(): Producer
mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest);
生成:ThreadHandoffProducer
/**
* Uses ExecutorService to move further computation to different thread
*/
public class ThreadHandoffProducer implements Producer {
@VisibleForTesting
protected static final String PRODUCER_NAME = "BackgroundThreadHandoffProducer";
private final Producer mInputProducer;
private final ThreadHandoffProducerQueue mThreadHandoffProducerQueue;
public ThreadHandoffProducer(final Producer inputProducer,
final ThreadHandoffProducerQueue inputThreadHandoffProducerQueue) {
mInputProducer = Preconditions.checkNotNull(inputProducer);
mThreadHandoffProducerQueue = inputThreadHandoffProducerQueue;
}
@Override
public void produceResults(final Consumer consumer, final ProducerContext context) {
final ProducerListener producerListener = context.getListener();
final String requestId = context.getId();
final StatefulProducerRunnable statefulRunnable = new StatefulProducerRunnable(
consumer,
producerListener,
PRODUCER_NAME,
requestId) {
@Override
protected void onSuccess(T ignored) {
producerListener.onProducerFinishWithSuccess(requestId, PRODUCER_NAME, null);
mInputProducer.produceResults(consumer, context);
}
@Override
protected void disposeResult(T ignored) {}
@Override
protected T getResult() throws Exception {
return null;
}
};
context.addCallbacks(
new BaseProducerContextCallbacks() {
@Override
public void onCancellationRequested() {
statefulRunnable.cancel();
mThreadHandoffProducerQueue.remove(statefulRunnable);
}
});
mThreadHandoffProducerQueue.addToQueueOrExecute(statefulRunnable);
}
}
produceResults()进行队列任务
/**
* Abstraction for computation.
*
* Computation expressed as StatefulRunnable can be cancelled, but only if it has not
* started yet.
*
*
For better decoupling of the code computing the result and the code that handles it, 4
* separate methods are provided: getResult, onSuccess, onFailure and onCancellation.
*
*
This runnable can be run only once. Subsequent calls to run method won't have any effect.
*/
abstract public class StatefulRunnable implements Runnable {
@Override
public final void run() {
if (!mState.compareAndSet(STATE_CREATED, STATE_STARTED)) {
return;
}
T result;
try {
result = getResult();
} catch (Exception e) {
mState.set(STATE_FAILED);
onFailure(e);
return;
}
mState.set(STATE_FINISHED);
try {
onSuccess(result);
} finally {
disposeResult(result);
}
}
}
完成回掉onSuccess,上面ThreadHandoffProducer:produceResults()&StatefulProducerRunnable:onSuccess():mInputProducer.produceResults(consumer, context);而这个mInputProducer是MultiplexProducer,看下描述:
/**
* Producer for combining multiple identical requests into a single request.
*
* Requests using the same key will be combined into a single request. This request is only
* cancelled when all underlying requests are cancelled, and returns values to all underlying
* consumers. If the request has already return one or more results but has not finished, then
* any requests with the same key will have the most recent result returned to them immediately.
* 也就是说这个类,把同样key合并成一个request,并且这个request如果被取消,那么下面所有的consumer将接收,
* 还有就是如果这个request提前返回,但没有完成,那么其它的request同样key将会立即拿到返回的。
*/
@ThreadSafe
public abstract class MultiplexProducer implements Producer {}
然后接着继续 mInputProducer.produceResults(forwardingConsumer,multiplexProducerContext); 当前这个在MultiplexProducer的mInputProducer是BitmapMemoryCacheProducer,然后接收produceResults()进行包装
/**
* Memory cache producer for the bitmap memory cache.
*/
public class BitmapMemoryCacheProducer implements Producer> {
public void produceResults(
final Consumer> consumer,
final ProducerContext producerContext) {
final ProducerListener listener = producerContext.getListener();
final String requestId = producerContext.getId();
listener.onProducerStart(requestId, getProducerName());
final ImageRequest imageRequest = producerContext.getImageRequest();
final Object callerContext = producerContext.getCallerContext();
final CacheKey cacheKey = mCacheKeyFactory.getBitmapCacheKey(imageRequest, callerContext);
CloseableReference 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> wrappedConsumer = wrapConsumer(consumer, cacheKey);
listener.onProducerFinishWithSuccess(
requestId,
getProducerName(),
listener.requiresExtraMap(requestId) ? ImmutableMap.of(VALUE_FOUND, "false") : null);
mInputProducer.produceResults(wrappedConsumer, producerContext);
}
}
最后又走 mInputProducer.produceResults(wrappedConsumer, producerContext);这个不同了,变成了DecodeProducer去进行图片修饰,前面有说
/**
* Decodes images.
*
* Progressive JPEGs are decoded progressively as new data arrives.
*/
public class DecodeProducer implements Producer> {
@Override
public void produceResults(
final Consumer> consumer,
final ProducerContext producerContext) {
final ImageRequest imageRequest = producerContext.getImageRequest();
ProgressiveDecoder progressiveDecoder;
if (!UriUtil.isNetworkUri(imageRequest.getSourceUri())) {
progressiveDecoder = new LocalImagesProgressiveDecoder(consumer, producerContext);
} else {
ProgressiveJpegParser jpegParser = new ProgressiveJpegParser(mByteArrayPool);
progressiveDecoder = new NetworkImagesProgressiveDecoder(
consumer,
producerContext,
jpegParser,
mProgressiveJpegConfig);
}
mInputProducer.produceResults(progressiveDecoder, producerContext);
}
}
mInputProducer这货不看了,这个是ResizeAndRotateProducer,旋转有关的,NetworkImagesProgressiveDecoder里面有jobSclude
/**
* Decodes images.
*
* Progressive JPEGs are decoded progressively as new data arrives.
*/
public class DecodeProducer implements Producer> {
public ProgressiveDecoder(
final Consumer> consumer,
final ProducerContext producerContext) {
super(consumer);
mProducerContext = producerContext;
mProducerListener = producerContext.getListener();
mImageDecodeOptions = producerContext.getImageRequest().getImageDecodeOptions();
mIsFinished = false;
JobRunnable job = new JobRunnable() {
@Override
public void run(EncodedImage encodedImage, boolean isLast) {
if (encodedImage != null) { // 这里开始接收到finsh
if (mDownsampleEnabled) {
ImageRequest request = producerContext.getImageRequest();
if (mDownsampleEnabledForNetwork ||
!UriUtil.isNetworkUri(request.getSourceUri())) {
encodedImage.setSampleSize(DownsampleUtil.determineSampleSize(
request, encodedImage));
}
}
doDecode(encodedImage, isLast);
}
}
};
mJobScheduler = new JobScheduler(mExecutor, job, mImageDecodeOptions.minDecodeIntervalMs);
mProducerContext.addCallbacks(
new BaseProducerContextCallbacks() {
@Override
public void onIsIntermediateResultExpectedChanged() {
if (mProducerContext.isIntermediateResultExpected()) {
mJobScheduler.scheduleJob();
}
}
});
}
}
然后job做完,会拿到回掉,走doDecode(encodedImage, isLast);
/**
* Decodes images.
*
* Progressive JPEGs are decoded progressively as new data arrives.
*/
public class DecodeProducer implements Producer> {
/** Performs the decode synchronously. */
private void doDecode(EncodedImage encodedImage, boolean isLast) {
if (isFinished() || !EncodedImage.isValid(encodedImage)) { // 校验
return;
}
try {
long queueTime = mJobScheduler.getQueuedTime();// 校验
int length = isLast ?// 校验
encodedImage.getSize() : getIntermediateImageEndOffset(encodedImage);
QualityInfo quality = isLast ? ImmutableQualityInfo.FULL_QUALITY : getQualityInfo();// 校验
// 这个还是ForwardingRequestListener,基本无用,因为里面包装的requstListener是空
mProducerListener.onProducerStart(mProducerContext.getId(), PRODUCER_NAME);
CloseableImage image = null;
try {
image = mImageDecoder.decodeImage(encodedImage, length, quality, mImageDecodeOptions); // 按图片类型加载
} catch (Exception e) {
Map extraMap = getExtraMap(image, queueTime, quality, isLast);
mProducerListener.
onProducerFinishWithFailure(mProducerContext.getId(), PRODUCER_NAME, e, extraMap);
handleError(e);
return;
}
Map extraMap = getExtraMap(image, queueTime, quality, isLast);
mProducerListener.
onProducerFinishWithSuccess(mProducerContext.getId(), PRODUCER_NAME, extraMap);
handleResult(image, isLast);
} finally {
EncodedImage.closeSafely(encodedImage);
}
}
}
mImageDecoder.decodeImage()将会调用ImageDecoder,这个类有点流弊,有谁知道'pinned'这个技术么,希望告诉我详细,关于内存的,以前bitmap保存在Ashmen后来sdk变高以后,bitmap挂载在java heap去维护了
Fresco 的 Image Pipeline 负责图片的获取和管理。
- 图片可以来自远程服务器,本地文件,或者Content Provider,本地资源。压缩后的文件缓存在本地存储中,Bitmap数据缓存在内存中。
- 在5.0系统之后,Image Pipeline 使用`pinned purgeables*将Bitmap数据存在native 内存中。这要求图片不使用时,要显示地释放内存。
- SimpleDraweeView 自动处理了这个释放过程,所以没有特殊情况,尽量使用SimpleDraweeView,在特殊的场合,如果有需要,也可以直接控制Image Pipeline。
Pinned purgeables behave as specified in {@link android.graphics.BitmapFactory.Options#inPurgeable}
public class BitmapFactory {
public static class Options {
/**
* @deprecated As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this is
* ignored.
*
* In {@link android.os.Build.VERSION_CODES#KITKAT} and below, if this
* is set to true, then the resulting bitmap will allocate its
* pixels such that they can be purged if the system needs to reclaim
* memory. In that instance, when the pixels need to be accessed again
* (e.g. the bitmap is drawn, getPixels() is called), they will be
* automatically re-decoded.
*
* For the re-decode to happen, the bitmap must have access to the
* encoded data, either by sharing a reference to the input
* or by making a copy of it. This distinction is controlled by
* inInputShareable. If this is true, then the bitmap may keep a shallow
* reference to the input. If this is false, then the bitmap will
* explicitly make a copy of the input data, and keep that. Even if
* sharing is allowed, the implementation may still decide to make a
* deep copy of the input data.
*
* While inPurgeable can help avoid big Dalvik heap allocations (from
* API level 11 onward), it sacrifices performance predictability since any
* image that the view system tries to draw may incur a decode delay which
* can lead to dropped frames. Therefore, most apps should avoid using
* inPurgeable to allow for a fast and fluid UI. To minimize Dalvik heap
* allocations use the {@link #inBitmap} flag instead.
*
* Note: This flag is ignored when used
* with {@link #decodeResource(Resources, int,
* android.graphics.BitmapFactory.Options)} or {@link #decodeFile(String,
* android.graphics.BitmapFactory.Options)}.
*/
@Deprecated
public boolean inPurgeable;
}
}
基本是说,inPurgeable,造成bitmap被系统回收通过pixels,因此,在fast和fluid ui(快速流畅)避免使用,GC时间长,为了使用小heap资源,sdk给inBitmap标志代替
关于Bitmap的回收机制
系统的Bitmap内存管理机制随着Android系统的演进可以分为三个阶段,关于这部分可以参考官网文章Managing Bitmap Memory。
- 2.3.3及以下:Bitmap的像素数据存储在native内存中,但依旧会计算在一个进程的内存上限之中。
- 3.0~4.4:Bitmap的像素数据存储在Java堆内存中,解码Bitmap时可以通过Options#inBitmap复用不再使用的Bitmap,从而减少系统gc。但要求被复用的Bitmap和新Bitmap的像素数据一样大。
- 5.0及以上:对于复用Bitmap的限制不再严格要求一样大,只要别复用的Bitmap的像素数据不小于新Bitmap即可。
/**
* Decodes images.
*
* ImageDecoder implements image type recognition and passes decode requests to
* specialized methods implemented by subclasses.
*
* On dalvik, it produces 'pinned' purgeable bitmaps.
*
*
Pinned purgeables behave as specified in
* {@link android.graphics.BitmapFactory.Options#inPurgeable} with one modification. The bitmap is
* 'pinned' so is never purged.
*
*
For API 21 and higher, this class produces standard Bitmaps, as purgeability is not supported
* on the most recent versions of Android.
*/
public class ImageDecoder {
/**
* Decodes image.
*
* @param encodedImage input image (encoded bytes plus meta data)
* @param length if image type supports decoding incomplete image then determines where
* the image data should be cut for decoding.
* @param qualityInfo quality information for the image
* @param options options that cange decode behavior
*/
public CloseableImage decodeImage(
final EncodedImage encodedImage,
final int length,
final QualityInfo qualityInfo,
final ImageDecodeOptions options) {
ImageFormat imageFormat = encodedImage.getImageFormat();
if (imageFormat == null || imageFormat == ImageFormat.UNKNOWN) {
imageFormat = ImageFormatChecker.getImageFormat_WrapIOException(
encodedImage.getInputStream());
}
switch (imageFormat) {
case UNKNOWN:
throw new IllegalArgumentException("unknown image format");
case JPEG:
return decodeJpeg(encodedImage, length, qualityInfo);
case GIF:
return decodeGif(encodedImage, options);
case WEBP_ANIMATED:
return decodeAnimatedWebp(encodedImage, options);
default:
return decodeStaticImage(encodedImage);
}
}
}
最后这个bitmap的Cahe会传到Multiplexer&ForwardingConsumer:consumer然后找到对应订阅Pair
好了,差不多介绍完主要的,细节我会持续补充的。