/** * 本文能夠隨意轉載到任何網站或者App, * BUT * 轉載也要按「基本法」, * 請註明原文出處和做者 */
官方源碼地址html
@Override protected DataSource<CloseableReference<CloseableImage>> getDataSourceForRequest( ImageRequest imageRequest, Object callerContext, boolean bitmapCacheOnly) { if (bitmapCacheOnly) { return mImagePipeline.fetchImageFromBitmapCache(imageRequest, callerContext); } else { return mImagePipeline.fetchDecodedImage(imageRequest, callerContext); } }
/** * Submits a request for execution and returns a DataSource representing the pending decoded * image(s). * <p>The returned DataSource must be closed once the client has finished with it. * @param imageRequest the request to submit * @return a DataSource representing the pending decoded image(s) */ public DataSource<CloseableReference<CloseableImage>> fetchDecodedImage( ImageRequest imageRequest, Object callerContext) { try { Producer<CloseableReference<CloseableImage>> producerSequence = mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest); return submitFetchRequest( producerSequence, imageRequest, ImageRequest.RequestLevel.FULL_FETCH, callerContext); } catch (Exception exception) { return DataSources.immediateFailedDataSource(exception); } }
private <T> DataSource<CloseableReference<T>> submitFetchRequest( Producer<CloseableReference<T>> producerSequence, ImageRequest imageRequest, ImageRequest.RequestLevel lowestPermittedRequestLevelOnSubmit, Object callerContext) { try { ImageRequest.RequestLevel lowestPermittedRequestLevel = ImageRequest.RequestLevel.getMax( imageRequest.getLowestPermittedRequestLevel(), lowestPermittedRequestLevelOnSubmit); SettableProducerContext settableProducerContext = new SettableProducerContext( 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); } }
protected AbstractProducerToDataSourceAdapter( Producer<T> producer, SettableProducerContext settableProducerContext, RequestListener requestListener) { mSettableProducerContext = settableProducerContext; mRequestListener = requestListener; mRequestListener.onRequestStart( settableProducerContext.getImageRequest(), mSettableProducerContext.getCallerContext(), mSettableProducerContext.getId(), mSettableProducerContext.isPrefetch()); producer.produceResults(createConsumer(), settableProducerContext); }
/** * Returns a sequence that can be used for a request for a decoded image. * * @param imageRequest the request that will be submitted * @return the sequence that should be used to process the request */ public Producer<CloseableReference<CloseableImage>> getDecodedImageProducerSequence( ImageRequest imageRequest) { Producer<CloseableReference<CloseableImage>> pipelineSequence = getBasicDecodedImageSequence(imageRequest); if (imageRequest.getPostprocessor() != null) { return getPostprocessorSequence(pipelineSequence); } else { return pipelineSequence; } }
private Producer<CloseableReference<CloseableImage>> getBasicDecodedImageSequence( ImageRequest imageRequest) { Preconditions.checkNotNull(imageRequest); Uri uri = imageRequest.getSourceUri(); 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); } }
/** * swallow result if prefetch -> bitmap cache get -> * background thread hand-off -> multiplex -> bitmap cache -> decode -> multiplex -> * encoded cache -> disk cache -> (webp transcode) -> network fetch. */ private synchronized Producer<CloseableReference<CloseableImage>> getNetworkFetchSequence() { if (mNetworkFetchSequence == null) { mNetworkFetchSequence = newBitmapCacheGetToDecodeSequence(getCommonNetworkFetchToEncodedMemorySequence()); } return mNetworkFetchSequence; }
/** * multiplex -> encoded cache -> disk cache -> (webp transcode) -> network fetch. */ private synchronized Producer<EncodedImage> getCommonNetworkFetchToEncodedMemorySequence() { if (mCommonNetworkFetchToEncodedMemorySequence == null) { Producer<EncodedImage> inputProducer = newEncodedCacheMultiplexToTranscodeSequence( mProducerFactory.newNetworkFetchProducer(mNetworkFetcher)); mCommonNetworkFetchToEncodedMemorySequence = ProducerFactory.newAddImageTransformMetaDataProducer(inputProducer); if (mResizeAndRotateEnabledForNetwork && !mDownsampleEnabled) { mCommonNetworkFetchToEncodedMemorySequence = mProducerFactory.newResizeAndRotateProducer( mCommonNetworkFetchToEncodedMemorySequence); } } return mCommonNetworkFetchToEncodedMemorySequence; }
/** * encoded cache multiplex -> encoded cache -> (disk cache) -> (webp transcode) * @param inputProducer producer providing the input to the transcode * @return encoded cache multiplex to webp transcode sequence */ private Producer<EncodedImage> newEncodedCacheMultiplexToTranscodeSequence( Producer<EncodedImage> inputProducer) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { inputProducer = mProducerFactory.newWebpTranscodeProducer(inputProducer); } inputProducer = mProducerFactory.newDiskCacheProducer(inputProducer); EncodedMemoryCacheProducer encodedMemoryCacheProducer = mProducerFactory.newEncodedMemoryCacheProducer(inputProducer); return mProducerFactory.newEncodedCacheKeyMultiplexProducer(encodedMemoryCacheProducer); }
public DiskCacheProducer newDiskCacheProducer( Producer<EncodedImage> inputProducer) { return new DiskCacheProducer( mDefaultBufferedDiskCache, mSmallImageBufferedDiskCache, mCacheKeyFactory, inputProducer); }
FileInputStream fileInputStream = new FileInputStream("/test.txt"); InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream); BufferedReader bufferedReader = new BufferedReader(inputSteamReader);
public DiskCacheProducer( BufferedDiskCache defaultBufferedDiskCache, BufferedDiskCache smallImageBufferedDiskCache, CacheKeyFactory cacheKeyFactory, Producer<EncodedImage> inputProducer) { mDefaultBufferedDiskCache = defaultBufferedDiskCache; mSmallImageBufferedDiskCache = smallImageBufferedDiskCache; mCacheKeyFactory = cacheKeyFactory; mInputProducer = inputProducer; } public void produceResults( final Consumer<EncodedImage> consumer, final ProducerContext producerContext) { ImageRequest imageRequest = producerContext.getImageRequest(); //若是diskcache disabled的話,那麼直接執行maybeStartInputProducer if (!imageRequest.isDiskCacheEnabled()) { maybeStartInputProducer(consumer, consumer, producerContext); return; } final ProducerListener listener = producerContext.getListener(); final String requestId = producerContext.getId(); listener.onProducerStart(requestId, PRODUCER_NAME); final CacheKey cacheKey = mCacheKeyFactory.getEncodedCacheKey(imageRequest); final BufferedDiskCache cache = imageRequest.getImageType() == ImageRequest.ImageType.SMALL ? mSmallImageBufferedDiskCache : mDefaultBufferedDiskCache; Continuation<EncodedImage, Void> continuation = new Continuation<EncodedImage, Void>() { //回調 @Override public Void then(Task<EncodedImage> task) throws Exception { //根據task是canceled,fault等狀態決定如何執行 if (task.isCancelled() || (task.isFaulted() && task.getError() instanceof CancellationException)) { listener.onProducerFinishWithCancellation(requestId, PRODUCER_NAME, null); consumer.onCancellation(); } else if (task.isFaulted()) { listener.onProducerFinishWithFailure(requestId, PRODUCER_NAME, task.getError(), null); //出錯了,就調用maybeStartInputProducer maybeStartInputProducer( consumer, new DiskCacheConsumer(consumer, cache, cacheKey), producerContext); } else { EncodedImage cachedReference = task.getResult(); if (cachedReference != null) { listener.onProducerFinishWithSuccess( requestId, PRODUCER_NAME, getExtraMap(listener, requestId, true)); consumer.onProgressUpdate(1); consumer.onNewResult(cachedReference, true); cachedReference.close(); } else { //沒有結果,就調用maybeStartInputProducer listener.onProducerFinishWithSuccess( requestId, PRODUCER_NAME, getExtraMap(listener, requestId, false)); maybeStartInputProducer( consumer, new DiskCacheConsumer(consumer, cache, cacheKey), producerContext); } } return null; } }; AtomicBoolean isCancelled = new AtomicBoolean(false); final Task<EncodedImage> diskCacheLookupTask = cache.get(cacheKey, isCancelled); //執行task,task其實就是從緩存中取結果,執行後,前面的continuation就會被回調 diskCacheLookupTask.continueWith(continuation); subscribeTaskForRequestCancellation(isCancelled, producerContext); } //調用mInputProducer的produceResults private void maybeStartInputProducer( Consumer<EncodedImage> consumerOfDiskCacheProducer, Consumer<EncodedImage> consumerOfInputProducer, ProducerContext producerContext) { if (producerContext.getLowestPermittedRequestLevel().getValue() >= ImageRequest.RequestLevel.DISK_CACHE.getValue()) { consumerOfDiskCacheProducer.onNewResult(null, true); return; } mInputProducer.produceResults(consumerOfInputProducer, producerContext); }
/** * Consumer that consumes results from next producer in the sequence. * * <p>The consumer puts the last result received into disk cache, and passes all results (success * or failure) down to the next consumer. */ private class DiskCacheConsumer extends DelegatingConsumer<EncodedImage, EncodedImage> { private final BufferedDiskCache mCache; private final CacheKey mCacheKey; private DiskCacheConsumer( final Consumer<EncodedImage> consumer, final BufferedDiskCache cache, final CacheKey cacheKey) { super(consumer); mCache = cache; mCacheKey = cacheKey; } //inputProducer的結果會從這裏返回,即newResult @Override public void onNewResultImpl(EncodedImage newResult, boolean isLast) { //返回的結果加入cache中 if (newResult != null && isLast) { mCache.put(mCacheKey, newResult); } //回調上一層procducer傳進來的consumer getConsumer().onNewResult(newResult, isLast); } }
/** * Producer for combining multiple identical requests into a single request. * * <p>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. * * @param <K> type of the key * @param <T> type of the closeable reference result that is returned to this producer */ @ThreadSafe public abstract class MultiplexProducer<K, T extends Closeable> implements Producer<T>
@Override public void produceResults(Consumer<T> consumer, ProducerContext context) { K key = getKey(context); Multiplexer multiplexer; boolean createdNewMultiplexer; // We do want to limit scope of this lock to guard only accesses to mMultiplexers map. // However what we would like to do here is to atomically lookup mMultiplexers, add new // consumer to consumers set associated with the map's entry and call consumer's callback with // last intermediate result. We should not do all of those things under this lock. do { createdNewMultiplexer = false; synchronized (this) { //根據key得到多路複用器,當緩存沒有的時候,才create一個,否則直接忽略 multiplexer = getExistingMultiplexer(key); if (multiplexer == null) { multiplexer = createAndPutNewMultiplexer(key); createdNewMultiplexer = true; } } // addNewConsumer may call consumer's onNewResult method immediately. For this reason // we release "this" lock. If multiplexer is removed from mMultiplexers in the meantime, // which is not very probable, then addNewConsumer will fail and we will be able to retry. } while (!multiplexer.addNewConsumer(consumer, context)); //若是前面沒有建立,也就是存在緩存的多路複用器,那麼就不會調用startInputProducerIfHasAttachedConsumers,而後inputProducer就不起做用了,這樣,就起到合併請求的做用 if (createdNewMultiplexer) { multiplexer.startInputProducerIfHasAttachedConsumers(); } }