public void init( Resources resources, DeferredReleaser deferredReleaser, DrawableFactory animatedDrawableFactory, Executor uiThreadExecutor, MemoryCache<CacheKey, CloseableImage> memoryCache, @Nullable ImmutableList<DrawableFactory> drawableFactories, @Nullable Supplier<Boolean> debugOverlayEnabledSupplier) { mResources = resources; mDeferredReleaser = deferredReleaser; mAnimatedDrawableFactory = animatedDrawableFactory; mUiThreadExecutor = uiThreadExecutor; mMemoryCache = memoryCache; mDrawableFactories = drawableFactories; mDebugOverlayEnabledSupplier = debugOverlayEnabledSupplier; }
public PipelineDraweeController newController( Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier, String id, CacheKey cacheKey, Object callerContext, @Nullable ImmutableList<DrawableFactory> customDrawableFactories) { Preconditions.checkState(mResources != null, "init() not called"); // Field values passed as arguments so that any subclass of PipelineDraweeControllerFactory // can simply override internalCreateController() and return a custom Drawee controller PipelineDraweeController controller = internalCreateController( mResources, mDeferredReleaser, mAnimatedDrawableFactory, mUiThreadExecutor, mMemoryCache, mDrawableFactories, customDrawableFactories, dataSourceSupplier, id, cacheKey, callerContext); if (mDebugOverlayEnabledSupplier != null) { controller.setDrawDebugOverlay(mDebugOverlayEnabledSupplier.get()); } return controller; }
protected PipelineDraweeController internalCreateController( Resources resources, DeferredReleaser deferredReleaser, DrawableFactory animatedDrawableFactory, Executor uiThreadExecutor, MemoryCache<CacheKey, CloseableImage> memoryCache, @Nullable ImmutableList<DrawableFactory> globalDrawableFactories, @Nullable ImmutableList<DrawableFactory> customDrawableFactories, Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier, String id, CacheKey cacheKey, Object callerContext) { PipelineDraweeController controller = new PipelineDraweeController( resources, deferredReleaser, animatedDrawableFactory, uiThreadExecutor, memoryCache, dataSourceSupplier, id, cacheKey, callerContext, globalDrawableFactories); controller.setCustomDrawableFactories(customDrawableFactories); return controller; }
/** * Writes to disk cache * @throws IOException */ private void writeToDiskCache( final CacheKey key, final EncodedImage encodedImage) { FLog.v(TAG, "About to write to disk-cache for key %s", key.getUriString()); try { mFileCache.insert( key, new WriterCallback() { @Override public void write(OutputStream os) throws IOException { mPooledByteStreams.copy(encodedImage.getInputStream(), os); } } ); FLog.v(TAG, "Successful disk-cache write for key %s", key.getUriString()); } catch (IOException ioe) { // Log failure // TODO: 3697790 FLog.w(TAG, ioe, "Failed to write to disk-cache for key %s", key.getUriString()); } }
public ExperimentalBitmapAnimationDrawableFactory( AnimatedDrawableBackendProvider animatedDrawableBackendProvider, ScheduledExecutorService scheduledExecutorServiceForUiThread, ExecutorService executorServiceForFramePreparing, MonotonicClock monotonicClock, PlatformBitmapFactory platformBitmapFactory, CountingMemoryCache<CacheKey, CloseableImage> backingCache, Supplier<Integer> cachingStrategySupplier, Supplier<Integer> numberOfFramesToPrepareSupplier) { mAnimatedDrawableBackendProvider = animatedDrawableBackendProvider; mScheduledExecutorServiceForUiThread = scheduledExecutorServiceForUiThread; mExecutorServiceForFramePreparing = executorServiceForFramePreparing; mMonotonicClock = monotonicClock; mPlatformBitmapFactory = platformBitmapFactory; mBackingCache = backingCache; mCachingStrategySupplier = cachingStrategySupplier; mNumberOfFramesToPrepareSupplier = numberOfFramesToPrepareSupplier; }
@Before public void setUp() { MockitoAnnotations.initMocks(this); MemoryCacheParams params = new MemoryCacheParams( 4 * ByteConstants.MB, 256, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); when(mMemoryCacheParamsSupplier.get()).thenReturn(params); CountingMemoryCache<CacheKey, CloseableImage> countingMemoryCache = BitmapCountingMemoryCacheFactory.get( mMemoryCacheParamsSupplier, mMemoryTrimmableRegistry, mPlatformBitmapFactory, true); mCacheKey = new SimpleCacheKey("key"); mAnimatedFrameCache = new AnimatedFrameCache(mCacheKey, countingMemoryCache); mFrame1 = CloseableReference.of(mock(CloseableImage.class)); mFrame2 = CloseableReference.of(mock(CloseableImage.class)); }
public static AnimatedFactory getAnimatedFactory( PlatformBitmapFactory platformBitmapFactory, ExecutorSupplier executorSupplier, CountingMemoryCache<CacheKey, CloseableImage> backingCache) { if (!sImplLoaded) { try { final Class<?> clazz = Class.forName("com.facebook.fresco.animation.factory.AnimatedFactoryV2Impl"); final Constructor<?> constructor = clazz.getConstructor( PlatformBitmapFactory.class, ExecutorSupplier.class, CountingMemoryCache.class); sImpl = (AnimatedFactory) constructor.newInstance( platformBitmapFactory, executorSupplier, backingCache); } catch (Throwable e) { // Head in the sand } if (sImpl != null) { sImplLoaded = true; } } return sImpl; }
/** * Probes whether the object corresponding to the mKey is in the cache. * Note that the act of probing touches the item (if present in cache), * thus changing its LRU timestamp. * <p> * This will be faster than retrieving the object, but it still has * file system accesses and should NOT be called on the UI thread. * * @param key the mKey to check * @return whether the keyed mValue is in the cache */ public boolean probe(final CacheKey key) { String resourceId = null; try { synchronized (mLock) { List<String> resourceIds = CacheKeyUtil.getResourceIds(key); for (int i = 0; i < resourceIds.size(); i++) { resourceId = resourceIds.get(i); if (mStorage.touch(resourceId, key)) { mResourceIndex.add(resourceId); return true; } } return false; } } catch (IOException e) { SettableCacheEvent cacheEvent = SettableCacheEvent.obtain() .setCacheKey(key) .setResourceId(resourceId) .setException(e); mCacheEventListener.onReadException(cacheEvent); cacheEvent.recycle(); return false; } }
@Override public void remove(CacheKey key) { synchronized (mLock) { try { String resourceId = null; List<String> resourceIds = CacheKeyUtil.getResourceIds(key); for (int i = 0; i < resourceIds.size(); i++) { resourceId = resourceIds.get(i); mStorage.remove(resourceId); mResourceIndex.remove(resourceId); } } catch (IOException e) { mCacheErrorLogger.logError( CacheErrorLogger.CacheErrorCategory.DELETE_FILE, TAG, "delete: " + e.getMessage(), e); } } }
@Override public boolean hasKey(final CacheKey key) { synchronized (mLock) { if (hasKeySync(key)) { return true; } try { String resourceId = null; List<String> resourceIds = CacheKeyUtil.getResourceIds(key); for (int i = 0; i < resourceIds.size(); i++) { resourceId = resourceIds.get(i); if (mStorage.contains(resourceId, key)) { mResourceIndex.add(resourceId); return true; } } return false; } catch (IOException e) { return false; } } }
@Override public CacheKey getPostprocessedBitmapCacheKey(ImageRequest request, Object callerContext) { final Postprocessor postprocessor = request.getPostprocessor(); final CacheKey postprocessorCacheKey; final String postprocessorName; if (postprocessor != null) { postprocessorCacheKey = postprocessor.getPostprocessorCacheKey(); postprocessorName = postprocessor.getClass().getName(); } else { postprocessorCacheKey = null; postprocessorName = null; } return new BitmapMemoryCacheKey( getCacheKeySourceUri(request.getSourceUri()), request.getResizeOptions(), request.getRotationOptions(), request.getImageDecodeOptions(), postprocessorCacheKey, postprocessorName, callerContext); }
/** * Verify that multiple threads can write to the cache at the same time. */ @Test public void testConcurrency() throws Exception { final CyclicBarrier barrier = new CyclicBarrier(3); WriterCallback writerCallback = new WriterCallback() { @Override public void write(OutputStream os) throws IOException { try { // Both threads will need to hit this barrier. If writing is serialized, // the second thread will never reach here as the first will hold // the write lock forever. barrier.await(10, TimeUnit.SECONDS); } catch (Exception e) { throw new RuntimeException(e); } } }; CacheKey key1 = new SimpleCacheKey("concurrent1"); CacheKey key2 = new SimpleCacheKey("concurrent2"); Thread t1 = runInsertionInSeparateThread(key1, writerCallback); Thread t2 = runInsertionInSeparateThread(key2, writerCallback); barrier.await(10, TimeUnit.SECONDS); t1.join(1000); t2.join(1000); }
private Thread runInsertionInSeparateThread(final CacheKey key, final WriterCallback callback) { Runnable runnable = new Runnable() { @Override public void run() { try { mCache.insert(key, callback); } catch (IOException e) { fail(); } } }; Thread thread = new Thread(runnable); thread.setDaemon(true); thread.start(); return thread; }
@Override public void onNewResultImpl(EncodedImage newResult, @Status int status) { // intermediate, null or uncacheable results are not cached, so we just forward them if (isNotLast(status) || newResult == null || statusHasAnyFlag(status, DO_NOT_CACHE_ENCODED | IS_PARTIAL_RESULT)) { getConsumer().onNewResult(newResult, status); return; } final ImageRequest imageRequest = mProducerContext.getImageRequest(); final CacheKey cacheKey = mCacheKeyFactory.getEncodedCacheKey(imageRequest, mProducerContext.getCallerContext()); if (imageRequest.getCacheChoice() == ImageRequest.CacheChoice.SMALL) { mSmallImageBufferedDiskCache.put(cacheKey, newResult); } else { mDefaultBufferedDiskCache.put(cacheKey, newResult); } getConsumer().onNewResult(newResult, status); }
private String verifyListenerOnWriteSuccessAndGetResourceId( CacheKey key, long itemSize) { ArgumentCaptor<CacheEvent> cacheEventCaptor = ArgumentCaptor.forClass(CacheEvent.class); mCacheEventListenerInOrder.verify(mCacheEventListener) .onWriteSuccess(cacheEventCaptor.capture()); CacheEvent cacheEvent = cacheEventCaptor.getValue(); CacheEventAssert.assertThat(cacheEvent) .isNotNull() .hasCacheKey(key) .hasItemSize(itemSize) .hasResourceIdSet(); return cacheEvent.getResourceId(); }
public static MemoryCache<CacheKey, PooledByteBuffer> get( final CountingMemoryCache<CacheKey, PooledByteBuffer> encodedCountingMemoryCache, final ImageCacheStatsTracker imageCacheStatsTracker) { imageCacheStatsTracker.registerEncodedMemoryCache(encodedCountingMemoryCache); MemoryCacheTracker memoryCacheTracker = new MemoryCacheTracker<CacheKey>() { @Override public void onCacheHit(CacheKey cacheKey) { imageCacheStatsTracker.onMemoryCacheHit(cacheKey); } @Override public void onCacheMiss() { imageCacheStatsTracker.onMemoryCacheMiss(); } @Override public void onCachePut() { imageCacheStatsTracker.onMemoryCachePut(); } }; return new InstrumentedMemoryCache<>(encodedCountingMemoryCache, memoryCacheTracker); }
private void writeCacheEntry( PrintStream writer, CountingMemoryCacheInspector.DumpInfoEntry<CacheKey, CloseableImage> entry) { if (!(entry.key instanceof BitmapMemoryCacheKey)) { writer.println("Undefined: " + entry.key.getClass()); } BitmapMemoryCacheKey cacheKey = (BitmapMemoryCacheKey) entry.key; writer.println(formatStrLocaleSafe( "size: %7.2fkB (%4d x %4d) key: %s, %s, duration: %dms", entry.value.get().getSizeInBytes() / KB, entry.value.get().getWidth(), entry.value.get().getHeight(), entry.key, cacheKey.getCallerContext(), RealtimeSinceBootClock.get().now() - cacheKey.getInBitmapCacheSince())); }
@Test public void testDoesNotWriteToIndexIfPartialResult() { when(mImageRequest.getMediaVariations()).thenReturn(mEmptyMediaVariations); setupInputProducerSuccessWithStatusFlags(Consumer.IS_PARTIAL_RESULT); mMediaVariationsFallbackProducer.produceResults(mConsumer, mProducerContext); verify(mConsumer).onNewResult(mIntermediateEncodedImage, Consumer.IS_PARTIAL_RESULT); verify(mConsumer) .onNewResult(mFinalEncodedImage, Consumer.IS_LAST | Consumer.IS_PARTIAL_RESULT); verify(mMediaVariationsIndex, never()).saveCachedVariant( anyString(), any(CacheChoice.class), any(CacheKey.class), any(EncodedImage.class)); }
@Override public CacheKey getPostprocessedBitmapCacheKey(ImageRequest request, Object callerContext) { final Postprocessor postprocessor = request.getPostprocessor(); final CacheKey postprocessorCacheKey; final String postprocessorName; if (postprocessor != null) { postprocessorCacheKey = postprocessor.getPostprocessorCacheKey(); postprocessorName = postprocessor.getClass().getName(); } else { postprocessorCacheKey = null; postprocessorName = null; } return new BitmapMemoryCacheKey( getCacheKeySourceUri(request.getSourceUri()).toString(), request.getResizeOptions(), request.getRotationOptions(), request.getImageDecodeOptions(), postprocessorCacheKey, postprocessorName, callerContext); }
public void produceResults( final Consumer<EncodedImage> consumer, final ProducerContext producerContext) { final ImageRequest imageRequest = producerContext.getImageRequest(); if (!imageRequest.isDiskCacheEnabled()) { mInputProducer.produceResults(consumer, producerContext); return; } producerContext.getListener().onProducerStart(producerContext.getId(), PRODUCER_NAME); final Uri uriForPartialCacheKey = createUriForPartialCacheKey(imageRequest); final CacheKey partialImageCacheKey = mCacheKeyFactory.getEncodedCacheKey( imageRequest, uriForPartialCacheKey, producerContext.getCallerContext()); final AtomicBoolean isCancelled = new AtomicBoolean(false); final Task<EncodedImage> diskLookupTask = mDefaultBufferedDiskCache.get(partialImageCacheKey, isCancelled); final Continuation<EncodedImage, Void> continuation = onFinishDiskReads(consumer, producerContext, partialImageCacheKey); diskLookupTask.continueWith(continuation); subscribeTaskForRequestCancellation(isCancelled, producerContext); }
public void produceResults( final Consumer<EncodedImage> consumer, final ProducerContext producerContext) { final ImageRequest imageRequest = producerContext.getImageRequest(); if (!imageRequest.isDiskCacheEnabled()) { maybeStartInputProducer(consumer, producerContext); return; } producerContext.getListener().onProducerStart(producerContext.getId(), PRODUCER_NAME); final CacheKey cacheKey = mCacheKeyFactory.getEncodedCacheKey(imageRequest, producerContext.getCallerContext()); final boolean isSmallRequest = (imageRequest.getCacheChoice() == CacheChoice.SMALL); final BufferedDiskCache preferredCache = isSmallRequest ? mSmallImageBufferedDiskCache : mDefaultBufferedDiskCache; final AtomicBoolean isCancelled = new AtomicBoolean(false); final Task<EncodedImage> diskLookupTask = preferredCache.get(cacheKey, isCancelled); final Continuation<EncodedImage, Void> continuation = onFinishDiskReads(consumer, producerContext); diskLookupTask.continueWith(continuation); subscribeTaskForRequestCancellation(isCancelled, producerContext); }
ProducerFactory createProducerFactory( Context context, ByteArrayPool byteArrayPool, ImageDecoder imageDecoder, ProgressiveJpegConfig progressiveJpegConfig, boolean downsampleEnabled, boolean resizeAndRotateEnabledForNetwork, boolean decodeCancellationEnabled, Supplier<Boolean> experimentalSmartResizingEnabled, ExecutorSupplier executorSupplier, PooledByteBufferFactory pooledByteBufferFactory, MemoryCache<CacheKey, CloseableImage> bitmapMemoryCache, MemoryCache<CacheKey, PooledByteBuffer> encodedMemoryCache, BufferedDiskCache defaultBufferedDiskCache, BufferedDiskCache smallImageBufferedDiskCache, MediaVariationsIndex mediaVariationsIndex, CacheKeyFactory cacheKeyFactory, PlatformBitmapFactory platformBitmapFactory, int bitmapPrepareToDrawMinSizeBytes, int bitmapPrepareToDrawMaxSizeBytes, boolean bitmapPrepareToDrawForPrefetch);
public BitmapMemoryCacheKey( String sourceString, @Nullable ResizeOptions resizeOptions, RotationOptions rotationOptions, ImageDecodeOptions imageDecodeOptions, @Nullable CacheKey postprocessorCacheKey, @Nullable String postprocessorName, Object callerContext) { mSourceString = Preconditions.checkNotNull(sourceString); mResizeOptions = resizeOptions; mRotationOptions = rotationOptions; mImageDecodeOptions = imageDecodeOptions; mPostprocessorCacheKey = postprocessorCacheKey; mPostprocessorName = postprocessorName; mHash = HashCodeUtil.hashCode( sourceString.hashCode(), (resizeOptions != null) ? resizeOptions.hashCode() : 0, rotationOptions.hashCode(), mImageDecodeOptions, mPostprocessorCacheKey, postprocessorName); mCallerContext = callerContext; mCacheTime = RealtimeSinceBootClock.get().now(); }
public PipelineDraweeController newController( Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier, String id, CacheKey cacheKey, Object callerContext) { return newController(dataSourceSupplier, id, cacheKey, callerContext, null); }
@Override public CacheKey getPostprocessorCacheKey() { return new SimpleCacheKey(String.format( (Locale) null, "text=%s,count=%d", mWatermarkText, mCount)); }
/** * Initializes this controller with the new data source supplier, id and caller context. This * allows for reusing of the existing controller instead of instantiating a new one. This method * should be called when the controller is in detached state. * * @param dataSourceSupplier data source supplier * @param id unique id for this controller * @param callerContext tag and context for this controller */ public void initialize( Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier, String id, CacheKey cacheKey, Object callerContext, @Nullable ImmutableList<DrawableFactory> customDrawableFactories) { super.initialize(id, callerContext); init(dataSourceSupplier); mCacheKey = cacheKey; setCustomDrawableFactories(customDrawableFactories); }
@DoNotStrip public AnimatedFactoryV2Impl( PlatformBitmapFactory platformBitmapFactory, ExecutorSupplier executorSupplier, CountingMemoryCache<CacheKey, CloseableImage> backingCache) { mPlatformBitmapFactory = platformBitmapFactory; mExecutorSupplier = executorSupplier; mBackingCache = backingCache; }
/** * 将图片插入缓存 * * @param key 保存文件的可以 * @param inputStream 图片转化成的InputStream * @return 是否插入成功 */ public static boolean insertImageToCache(String key, InputStream inputStream) { try { CacheKey cacheKey = DefaultCacheKeyFactory.getInstance().getEncodedCacheKey(ImageRequest.fromUri(key), null); ImagePipelineFactory.getInstance().getMainFileCache().insert(cacheKey, WriterCallbacks.from(inputStream)); } catch (IOException e) { e.printStackTrace(); return false; } finally { CloseUtil.close(inputStream); } return true; }
public AnimatedFrameCache( CacheKey imageCacheKey, final CountingMemoryCache<CacheKey, CloseableImage> backingCache) { mImageCacheKey = imageCacheKey; mBackingCache = backingCache; mFreeItemsPool = new LinkedHashSet<>(); mEntryStateObserver = new CountingMemoryCache.EntryStateObserver<CacheKey>() { @Override public void onExclusivityChanged(CacheKey key, boolean isExclusive) { AnimatedFrameCache.this.onReusabilityChange(key, isExclusive); } }; }
public synchronized void onReusabilityChange(CacheKey key, boolean isReusable) { if (isReusable) { mFreeItemsPool.add(key); } else { mFreeItemsPool.remove(key); } }
/** * Gets the image to be reused, or null if there is no such image. * * <p> The returned image is the least recently used image that has no more clients referencing * it, and it has not yet been evicted from the cache. * * <p> The client can freely modify the bitmap of the returned image and can cache it again * without any restrictions. */ @Nullable public CloseableReference<CloseableImage> getForReuse() { while (true) { CacheKey key = popFirstFreeItemKey(); if (key == null) { return null; } CloseableReference<CloseableImage> imageRef = mBackingCache.reuse(key); if (imageRef != null) { return imageRef; } } }
@Nullable private synchronized CacheKey popFirstFreeItemKey() { CacheKey cacheKey = null; Iterator<CacheKey> iterator = mFreeItemsPool.iterator(); if (iterator.hasNext()) { cacheKey = iterator.next(); iterator.remove(); } return cacheKey; }
public static CountingMemoryCache<CacheKey, CloseableImage> get( Supplier<MemoryCacheParams> bitmapMemoryCacheParamsSupplier, MemoryTrimmableRegistry memoryTrimmableRegistry, PlatformBitmapFactory platformBitmapFactory, boolean isExternalCreatedBitmapLogEnabled, CountingMemoryCache.CacheTrimStrategy trimStrategy) { ValueDescriptor<CloseableImage> valueDescriptor = new ValueDescriptor<CloseableImage>() { @Override public int getSizeInBytes(CloseableImage value) { return value.getSizeInBytes(); } }; CountingMemoryCache<CacheKey, CloseableImage> countingCache = new CountingMemoryCache<>( valueDescriptor, trimStrategy, bitmapMemoryCacheParamsSupplier, platformBitmapFactory, isExternalCreatedBitmapLogEnabled); memoryTrimmableRegistry.registerMemoryTrimmable(countingCache); return countingCache; }
/** * Retrieves the file corresponding to the mKey, if it is in the cache. Also * touches the item, thus changing its LRU timestamp. If the file is not * present in the file cache, returns null. * <p> * This should NOT be called on the UI thread. * * @param key the mKey to check * @return The resource if present in cache, otherwise null */ @Override public BinaryResource getResource(final CacheKey key) { String resourceId = null; SettableCacheEvent cacheEvent = SettableCacheEvent.obtain() .setCacheKey(key); try { synchronized (mLock) { BinaryResource resource = null; List<String> resourceIds = CacheKeyUtil.getResourceIds(key); for (int i = 0; i < resourceIds.size(); i++) { resourceId = resourceIds.get(i); cacheEvent.setResourceId(resourceId); resource = mStorage.getResource(resourceId, key); if (resource != null) { break; } } if (resource == null) { mCacheEventListener.onMiss(cacheEvent); mResourceIndex.remove(resourceId); } else { mCacheEventListener.onHit(cacheEvent); mResourceIndex.add(resourceId); } return resource; } } catch (IOException ioe) { mCacheErrorLogger.logError( CacheErrorLogger.CacheErrorCategory.GENERIC_IO, TAG, "getResource", ioe); cacheEvent.setException(ioe); mCacheEventListener.onReadException(cacheEvent); return null; } finally { cacheEvent.recycle(); } }
/** * Creates a temp file for writing outside the session lock */ private DiskStorage.Inserter startInsert( final String resourceId, final CacheKey key) throws IOException { maybeEvictFilesInCacheDir(); return mStorage.insert(resourceId, key); }
/** * Commits the provided temp file to the cache, renaming it to match * the cache's hashing convention. */ private BinaryResource endInsert( final DiskStorage.Inserter inserter, final CacheKey key, String resourceId) throws IOException { synchronized (mLock) { BinaryResource resource = inserter.commit(key); mResourceIndex.add(resourceId); mCacheStats.increment(resource.size(), 1); return resource; } }
@Override public BinaryResource insert(CacheKey key, WriterCallback callback) throws IOException { // Write to a temp file, then move it into place. This allows more parallelism // when writing files. SettableCacheEvent cacheEvent = SettableCacheEvent.obtain() .setCacheKey(key); mCacheEventListener.onWriteAttempt(cacheEvent); String resourceId; synchronized (mLock) { // for multiple resource ids associated with the same image, we only write one file resourceId = CacheKeyUtil.getFirstResourceId(key); } cacheEvent.setResourceId(resourceId); try { // getting the file is synchronized DiskStorage.Inserter inserter = startInsert(resourceId, key); try { inserter.writeData(callback, key); // Committing the file is synchronized BinaryResource resource = endInsert(inserter, key, resourceId); cacheEvent.setItemSize(resource.size()) .setCacheSize(mCacheStats.getSize()); mCacheEventListener.onWriteSuccess(cacheEvent); return resource; } finally { if (!inserter.cleanUp()) { FLog.e(TAG, "Failed to delete temp file"); } } } catch (IOException ioe) { cacheEvent.setException(ioe); mCacheEventListener.onWriteException(cacheEvent); FLog.e(TAG, "Failed inserting a file into the cache", ioe); throw ioe; } finally { cacheEvent.recycle(); } }
protected Pair<CacheKey, ImageRequest.RequestLevel> getKey( ProducerContext producerContext) { return Pair.create( mCacheKeyFactory.getBitmapCacheKey( producerContext.getImageRequest(), producerContext.getCallerContext()), producerContext.getLowestPermittedRequestLevel()); }
@Override protected Consumer<CloseableReference<CloseableImage>> wrapConsumer( final Consumer<CloseableReference<CloseableImage>> consumer, final CacheKey cacheKey) { // since this cache is read-only, we can pass our consumer directly to the next producer return consumer; }
@Test public void testCacheEventListener() throws Exception { // 1. Add first cache file CacheKey key1 = new SimpleCacheKey("foo"); int value1Size = 101; byte[] value1 = new byte[value1Size]; value1[80] = 'c'; // just so it's not all zeros for the equality test below. BinaryResource resource1 = mCache.insert(key1, WriterCallbacks.from(value1)); verifyListenerOnWriteAttempt(key1); String resourceId1 = verifyListenerOnWriteSuccessAndGetResourceId(key1, value1Size); BinaryResource resource1Again = mCache.getResource(key1); assertEquals(resource1, resource1Again); verifyListenerOnHit(key1, resourceId1); BinaryResource resource1Again2 = mCache.getResource(key1); assertEquals(resource1, resource1Again2); verifyListenerOnHit(key1, resourceId1); SimpleCacheKey missingKey = new SimpleCacheKey("nonexistent_key"); BinaryResource res2 = mCache.getResource(missingKey); assertNull(res2); verifyListenerOnMiss(missingKey); mCache.clearAll(); verify(mCacheEventListener).onCleared(); verifyNoMoreInteractions(mCacheEventListener); }