/* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.fresco.animation.bitmap.cache; import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; import android.graphics.Bitmap; import com.facebook.common.references.CloseableReference; import com.facebook.fresco.animation.bitmap.BitmapAnimationBackend; import com.facebook.fresco.animation.bitmap.BitmapFrameCache; import com.facebook.imageutils.BitmapUtil; /** * Simple bitmap cache that keeps the last frame and reuses it if possible. */ public class KeepLastFrameCache implements BitmapFrameCache { private static final int FRAME_NUMBER_UNSET = -1; private int mLastFrameNumber = FRAME_NUMBER_UNSET; @Nullable private FrameCacheListener mFrameCacheListener; @GuardedBy("this") @Nullable private CloseableReference<Bitmap> mLastBitmapReference; @Nullable @Override public synchronized CloseableReference<Bitmap> getCachedFrame(int frameNumber) { if (mLastFrameNumber == frameNumber) { return CloseableReference.cloneOrNull(mLastBitmapReference); } return null; } @Nullable @Override public synchronized CloseableReference<Bitmap> getFallbackFrame(int frameNumber) { return CloseableReference.cloneOrNull(mLastBitmapReference); } @Override public synchronized CloseableReference<Bitmap> getBitmapToReuseForFrame( int frameNumber, int width, int height) { try { return CloseableReference.cloneOrNull(mLastBitmapReference); } finally { closeAndResetLastBitmapReference(); } } @Override public synchronized boolean contains(int frameNumber) { return frameNumber == mLastFrameNumber && CloseableReference.isValid(mLastBitmapReference); } @Override public synchronized int getSizeInBytes() { return mLastBitmapReference == null ? 0 : BitmapUtil.getSizeInBytes(mLastBitmapReference.get()); } @Override public synchronized void clear() { closeAndResetLastBitmapReference(); } @Override public synchronized void onFrameRendered( int frameNumber, CloseableReference<Bitmap> bitmapReference, @BitmapAnimationBackend.FrameType int frameType) { if (bitmapReference != null && mLastBitmapReference != null && bitmapReference.get().equals(mLastBitmapReference.get())) { return; } CloseableReference.closeSafely(mLastBitmapReference); if (mFrameCacheListener != null && mLastFrameNumber != FRAME_NUMBER_UNSET) { mFrameCacheListener.onFrameEvicted(this, mLastFrameNumber); } mLastBitmapReference = CloseableReference.cloneOrNull(bitmapReference); if (mFrameCacheListener != null) { mFrameCacheListener.onFrameCached(this, frameNumber); } mLastFrameNumber = frameNumber; } @Override public void onFramePrepared( int frameNumber, CloseableReference<Bitmap> bitmapReference, @BitmapAnimationBackend.FrameType int frameType) { } @Override public void setFrameCacheListener(FrameCacheListener frameCacheListener) { mFrameCacheListener = frameCacheListener; } private synchronized void closeAndResetLastBitmapReference() { if (mFrameCacheListener != null && mLastFrameNumber != FRAME_NUMBER_UNSET) { mFrameCacheListener.onFrameEvicted(this, mLastFrameNumber); } CloseableReference.closeSafely(mLastBitmapReference); mLastBitmapReference = null; mLastFrameNumber = FRAME_NUMBER_UNSET; } }