Fresco Gif加载解析

Fresco Gif加载解析

普通Gif加载

val controller = Fresco.newDraweeControllerBuilder()
            .setAutoPlayAnimations(true)//就是添加了这一句代码,就可以播放动图
            .setImageRequest(request)
            .setOldController(sivBanner?.controller)
            .build()

sivBanner?.controller = controller

先看性能表现效果图:


FrescoGif_GC.jpeg

FrescoGif_CPU.jpeg

FrescoGif_Memory.jpeg

从上面三张图可以看的出来普通的加载会频繁GC,这种情况比较严重,并且CPU使用率比较高,50%左右,并且通过Dump内存的分布可以看出来,Fresco的缓存了太多的图片,并且占用的是BitmapMemory,这3种表现在加载Gif的时候是无法接受的。我们希望达到的效果是CPU的使用率能够降下来,并且尽量少的占用Fresco的内存缓存,如果想达到目标,只能去看看Fresco的Gif加载的代码。

这里再提一点,为什么会想到去优化Fresco的Gif加载。因为看到android-gif-drawable的表现后,发现android-gif-drawable其实是依赖于GifLib来做的底层支撑,而Fresco也是基于GifLib。因为两个框架底层用的是一样的,那么从理论上来说,Fresco就应该有优化的空间。

Gif加载流程分析

先从头分析下
AbstractDraweeController::onNewResultInternal()会把生成的Drawable设置给DraweeHierachy,先找到最终生成的是什么Drawable ----->
PipelineDraweeController::createDrawable()---->
mDefaultDrawableFactory::createDrawable()---->
mAnimatedDrawableFactory::createDrawable()---->
ExperimentalBitmapAnimationDrawableFactory::createDrawable()---->
最终生成的是AnimatedDrawable2

AnimationDrawableBackend.jpg
AnimationDrawable.jpg

  @Override
  public AnimatedDrawable2 createDrawable(CloseableImage image) {
    return new AnimatedDrawable2(
    //生成AnimationBackend,传入AnimatedDrawable2
        createAnimationBackend(
            ((CloseableAnimatedImage) image).getImageResult()));
  }
  
  
  private AnimationBackend createAnimationBackend(AnimatedImageResult animatedImageResult) {
    AnimatedDrawableBackend animatedDrawableBackend =
        createAnimatedDrawableBackend(animatedImageResult);

    //设置帧缓存
    BitmapFrameCache bitmapFrameCache = createBitmapFrameCache(animatedImageResult);
    BitmapFrameRenderer bitmapFrameRenderer =
        new AnimatedDrawableBackendFrameRenderer(bitmapFrameCache, animatedDrawableBackend);

    int numberOfFramesToPrefetch = mNumberOfFramesToPrepareSupplier.get();//预先获取帧的个数
    BitmapFramePreparationStrategy bitmapFramePreparationStrategy = null;
    BitmapFramePreparer bitmapFramePreparer = null;//图片帧的准备者
    if (numberOfFramesToPrefetch > 0) {
      bitmapFramePreparationStrategy =
          new FixedNumberBitmapFramePreparationStrategy(numberOfFramesToPrefetch);
      bitmapFramePreparer = createBitmapFramePreparer(bitmapFrameRenderer);
    }

    BitmapAnimationBackend bitmapAnimationBackend = new BitmapAnimationBackend(
        mPlatformBitmapFactory,
        bitmapFrameCache,
        new AnimatedDrawableBackendAnimationInformation(animatedDrawableBackend),
        bitmapFrameRenderer,
        bitmapFramePreparationStrategy,
        bitmapFramePreparer);

    return AnimationBackendDelegateWithInactivityCheck.createForBackend(
        bitmapAnimationBackend,
        mMonotonicClock,
        mScheduledExecutorServiceForUiThread);
  }

最终设置给DraweeHierachy的是AnimatedDrawable2,
先看下AnmatedDrawable2


AnimatedDrawable2

@Override
  public void draw(Canvas canvas) {

    .....
    
    // 绘制当前帧,把绘制的操作交给了mAnimationBackend
    boolean frameDrawn = mAnimationBackend.drawFrame(this, canvas, frameNumberToDraw);

    ....

    long targetRenderTimeForNextFrameMs = FrameScheduler.NO_NEXT_TARGET_RENDER_TIME;
    long scheduledRenderTimeForNextFrameMs = -1;
    long actualRenderTimeEnd = now();
    if (mIsRunning) {
      // Schedule the next frame if needed.
      targetRenderTimeForNextFrameMs =
          mFrameScheduler.getTargetRenderTimeForNextFrameMs(actualRenderTimeEnd - mStartTimeMs);
      if (targetRenderTimeForNextFrameMs != FrameScheduler.NO_NEXT_TARGET_RENDER_TIME) {
        scheduledRenderTimeForNextFrameMs =
            targetRenderTimeForNextFrameMs + mFrameSchedulingDelayMs;
        //绘制下一帧
        scheduleNextFrame(scheduledRenderTimeForNextFrameMs);
      }
    }
    ....

  }
  
  
  private void scheduleNextFrame(long targetAnimationTimeMs) {
    mExpectedRenderTimeMs = mStartTimeMs + targetAnimationTimeMs;
    scheduleSelf(mInvalidateRunnable, mExpectedRenderTimeMs);
  }
  
  
  private final Runnable mInvalidateRunnable = new Runnable() {
    @Override
    public void run() {
      unscheduleSelf(mInvalidateRunnable);
   
      //绘制下一帧
      invalidateSelf();
    }
  };

BitmapAnimationBackend::drawFrame()---->
BitmapAnimationBackend::drawFrameOrFallback()---->


@Override
  public boolean drawFrame(
      Drawable parent,
      Canvas canvas,
      int frameNumber) {
    ...

    //绘制当前帧
    boolean drawn = drawFrameOrFallback(canvas, frameNumber, FRAME_TYPE_CACHED);

    ...

    //准备下面的几帧
    if (mBitmapFramePreparationStrategy != null && mBitmapFramePreparer != null) {
      mBitmapFramePreparationStrategy.prepareFrames(
          mBitmapFramePreparer,
          mBitmapFrameCache,
          this,
          frameNumber);
    }

    return drawn;
  }
  
  
 //drawFrameOrFallback,绘制当前帧或者后备帧
 //1. FRAME_TYPE_CACHED  首先尝试从帧缓存里面取当前帧的bitmap,如果取到就绘制和缓存当前帧
 //2. FRAME_TYPE_REUSED 尝试获取可以重用的bitmap,获取到就绘制和缓存当前帧
 //3. FRAME_TYPE_CREATED 创建Bitmap,然后绘制和缓存当前帧
 //4. FRAME_TYPE_FALLBACK 获取给定帧编号的后备帧。 如果绘制帧的所有其他尝试都失败,则调用此方法。 返回的Bitmap可以是最后绘制的帧(如果有的话)
 
  private boolean drawFrameOrFallback(Canvas canvas, int frameNumber, @FrameType int frameType) {
    CloseableReference bitmapReference = null;
    boolean drawn = false;
    int nextFrameType = FRAME_TYPE_UNKNOWN;

    try {
      switch (frameType) {
        case FRAME_TYPE_CACHED:
          bitmapReference = mBitmapFrameCache.getCachedFrame(frameNumber);
          drawn = drawBitmapAndCache(frameNumber, bitmapReference, canvas, FRAME_TYPE_CACHED);
          nextFrameType = FRAME_TYPE_REUSED;
          break;

        case FRAME_TYPE_REUSED:
          bitmapReference =
              mBitmapFrameCache.getBitmapToReuseForFrame(frameNumber, mBitmapWidth, mBitmapHeight);
          // Try to render the frame and draw on the canvas immediately after
          drawn = renderFrameInBitmap(frameNumber, bitmapReference) &&
              drawBitmapAndCache(frameNumber, bitmapReference, canvas, FRAME_TYPE_REUSED);
          nextFrameType = FRAME_TYPE_CREATED;
          break;

        case FRAME_TYPE_CREATED:
          try {
            bitmapReference =
                mPlatformBitmapFactory.createBitmap(mBitmapWidth, mBitmapHeight, mBitmapConfig);
          } catch (RuntimeException e) {
                        return false;
          }
          drawn = renderFrameInBitmap(frameNumber, bitmapReference) &&
              drawBitmapAndCache(frameNumber, bitmapReference, canvas, FRAME_TYPE_CREATED);
          nextFrameType = FRAME_TYPE_FALLBACK;
          break;

        case FRAME_TYPE_FALLBACK:
        //获取给定帧编号的后备帧。 如果绘制帧的所有其他尝试都失败,则调用此方法。 返回的位图例如可以是最后绘制的帧(如果有的话)。
          bitmapReference = mBitmapFrameCache.getFallbackFrame(frameNumber);
          drawn = drawBitmapAndCache(frameNumber, bitmapReference, canvas, FRAME_TYPE_FALLBACK);
          break;

        default:
          return false;
      }
    } finally {
      CloseableReference.closeSafely(bitmapReference);
    }

    if (drawn || nextFrameType == FRAME_TYPE_UNKNOWN) {
      return drawn;
    } else {
      return drawFrameOrFallback(canvas, frameNumber, nextFrameType);
    }
  }
  
  ...
  //绘制和缓存当前帧
private boolean drawBitmapAndCache(
      int frameNumber,
      @Nullable CloseableReference bitmapReference,
      Canvas canvas,
      @FrameType int frameType) {
    if (!CloseableReference.isValid(bitmapReference)) {
      return false;
    }
    //这里的bitmap是经过native层修改像素信息后的下一帧bitmap
    if (mBounds == null) {
      canvas.drawBitmap(bitmapReference.get(), 0f, 0f, mPaint);
    } else {
      canvas.drawBitmap(bitmapReference.get(), null, mBounds, mPaint);
    }

    // 这里时告诉BitmapFrameCache,当前帧绘制好了,可以做响应的缓存操作
    if (frameType != FRAME_TYPE_FALLBACK) {
      mBitmapFrameCache.onFrameRendered(
          frameNumber,
          bitmapReference,
          frameType);
    }

    if (mFrameListener != null) {
      mFrameListener.onFrameDrawn(this, frameNumber, frameType);
    }
    return true;
  }
  

 /**
   * 尝试在给定的bitmap上绘制当前帧,如果绘制失败,bitmap引用会关闭并且返回false,如果绘制成功,这个bitmap就会被draw,并且在绘制完成后会自动关闭
   */
  private boolean renderFrameInBitmap(
      int frameNumber,
      @Nullable CloseableReference targetBitmap) {
    ...
    //继续向下传递,渲染当前帧
    boolean frameRendered =
        mBitmapFrameRenderer.renderFrame(frameNumber, targetBitmap.get());
    if (!frameRendered) {
      CloseableReference.closeSafely(targetBitmap);
    }
    return frameRendered;
  }
  
 

renderFrameInBitmap() 在Bitmap上渲染当前帧,这个方法就跟android-gif-drawable中的renderFrame()是一样的作用,就是在native层修改掉bitmap的像素信息,然后调用drawBitmapAndCache()

BitmapAnimationBackend::renderFrameInBitmap()---->
AnimatedDrawableBackendFrameRenderer::renderFrame()---->
AnimatedImageCompositor::renderFrame()---->
AnimatedDrawableBackendImpl::renderFrame()---->
AnimatedDrawableBackendImpl::renderImageSupportsScaling()---->
GifFrame::renderFrame()---->
GifFrame::nativeRenderFrame()---->

下面分析下最终渲染帧的地方,最终传到了AnimatedDrawableBackend 实现类是AnimatedDrawableBackendImpl

private @Nullable Bitmap mTempBitmap;

@Override
  public void renderFrame(int frameNumber, Canvas canvas) {
    AnimatedImageFrame frame  = mAnimatedImage.getFrame(frameNumber);
    try {
      if (mAnimatedImage.doesRenderSupportScaling()) {
        renderImageSupportsScaling(canvas, frame);
      } else {
        renderImageDoesNotSupportScaling(canvas, frame);
      }
    } finally {
      frame.dispose();
    }
  }


 private void renderImageSupportsScaling(Canvas canvas, AnimatedImageFrame frame) {
 
     ....
    synchronized (this) {
    ...
    
      //修改mTempBitmap的像素信息
      frame.renderFrame(frameWidth, frameHeight, mTempBitmap);
     
    ...
     //把mTempBitmap的像素信息,渲染到canvas上Bitmap的,也就是在drawFrameOrFallback传入进来的bitmap
      canvas.drawBitmap(mTempBitmap, mRenderSrcRect, mRenderDstRect, null);
    }
  }
  

gif.cpp


void GifFrame_nativeRenderFrame(
    JNIEnv* pEnv,
    jobject thiz,
    jint width,
    jint height,
    jobject bitmap) {
  ....

  uint8_t* pixels;
  if (AndroidBitmap_lockPixels(pEnv, bitmap, (void**) &pixels) != ANDROID_BITMAP_RESULT_SUCCESS) {
    throwIllegalStateException(pEnv, "Bad bitmap");
    return;
  }
  blitNormal(
      pixels,
      width,
      height,
      bitmapInfo.stride,
      pSavedImage,
      spNativeContext->spGifWrapper->getRasterBits(),
      pColorMap,
      spNativeContext->transparentIndex);
  AndroidBitmap_unlockPixels(pEnv, bitmap);
}
根据上面的代码可以看出来,最终也是先锁定像素信息,然后修改,最终unlock。



static void blitNormal(
    uint8_t* pDest,
    int destWidth,
    int destHeight,
    int destStride,
    const SavedImage* pFrame,
    const GifByteType* pSrcRasterBits,
    const ColorMapObject* cmap,
    int transparentIndex) {
  GifWord copyWidth = pFrame->ImageDesc.Width;
  if (copyWidth > destWidth) {
    copyWidth = destWidth;
  }

  GifWord copyHeight = pFrame->ImageDesc.Height;
  if (copyHeight > destHeight) {
    copyHeight = destHeight;
  }

  for (; copyHeight > 0; copyHeight--) {
    blitLine((PixelType32*) pDest, pSrcRasterBits, cmap, transparentIndex, copyWidth);
    pSrcRasterBits += pFrame->ImageDesc.Width;
    pDest += destStride;
  }
}

static void blitLine(
    PixelType32* pDest,
    const GifByteType* pSource,
    const ColorMapObject* pColorMap,
    int transparentIndex,
    int width) {
    //std::transform 应用给定的函数到范围并存储结果于始于 d_first 的另一范围。

    // 1) 应用一元函数 [=] (uint8_t color) 到 [pSource, pSource + width) 所定义的范围。
    
    /**
    *对于一元操作,将op应用于[first1, last1]范围内的每个元素,并将每个操作返回的值存储在以result开头的范围内。给定的op将被连续调用last1-first1+1次。op可以是函数指针或函数对象或lambda表达式。
    */
  std::transform(pSource, pSource + width, pDest, [=] (uint8_t color) {
    if (color == transparentIndex) {
      return TRANSPARENT;
    }
    return getColorFromTable(color, pColorMap);
  });
}

这是最终绘制当前帧的地方,在AnimatedDrawableBackendImpl类中,有个属性 mTempBitmap,其实这个bitmap就是传给native层,修改像素信息为下一帧的像素后,响应到Java层的。最后把MtempBitmap的像素信息渲染到canvas上的Bitmap,也就是在drawFrameOrFallback传入进来的bitmap

然后再回到BitmapAnimationBackend::drawFrameOrFallback(),renderFrameInBitmap方法走完了,还需要继续走drawBitmapAndCache()


private boolean drawBitmapAndCache(
      int frameNumber,
      @Nullable CloseableReference bitmapReference,
      Canvas canvas,
      @FrameType int frameType) {
    if (!CloseableReference.isValid(bitmapReference)) {
      return false;
    }
    //这里bitmap是承载了经过native层修改像素信息后的bitmap
    if (mBounds == null) {
      canvas.drawBitmap(bitmapReference.get(), 0f, 0f, mPaint);
    } else {
      canvas.drawBitmap(bitmapReference.get(), null, mBounds, mPaint);
    }

    // 这里传给了BitmapFrameCache,当前帧绘制好了,可以做响应的缓存操作
    if (frameType != FRAME_TYPE_FALLBACK) {
      mBitmapFrameCache.onFrameRendered(
          frameNumber,
          bitmapReference,
          frameType);
    }

    if (mFrameListener != null) {
      mFrameListener.onFrameDrawn(this, frameNumber, frameType);
    }
    return true;
  }

BitmapFrameCache

BitmapFrescoFrameCache.jpg

FrescoFramCache:Fresco加载Gif默认的BitmapFrameCache,AnimatedFrameCache是操作帧缓存的

KeepLastFrameCache:保存上一帧的Bitmap,用于复用

NoOpCache: 无操作缓存,就是没缓存

BitmapFramCahce的创建

BitmapFrameCache创建的地方在:

AnimatedFactoryV2Impl
public class AnimatedFactoryV2Impl implements AnimatedFactory {

private static final int NUMBER_OF_FRAMES_TO_PREPARE = 3;

    ...
private DrawableFactory createDrawableFactory() {
        //传递给ExperimentalBitmapAnimationDrawableFactory,设置BitmapFrameCache的实现类
        Supplier cachingStrategySupplier = new Supplier() {
            @Override
            public Integer get() {
                return ExperimentalBitmapAnimationDrawableFactory.CACHING_STRATEGY_NO_CACHE;
            }
        };


        final SerialExecutorService serialExecutorServiceForFramePreparing =
                new DefaultSerialExecutorService(mExecutorSupplier.forDecode());
        //设置动图的预先加载的帧数,默认是3帧
        Supplier numberOfFramesToPrepareSupplier = new Supplier() {
            @Override
            public Integer get() {
                return NUMBER_OF_FRAMES_TO_PREPARE;
            }
        };

        return new ExperimentalBitmapAnimationDrawableFactory(
                getAnimatedDrawableBackendProvider(),
                UiThreadImmediateExecutorService.getInstance(),
                serialExecutorServiceForFramePreparing,
                RealtimeSinceBootClock.get(),
                mPlatformBitmapFactory,
                mBackingCache,
                cachingStrategySupplier,
                numberOfFramesToPrepareSupplier);
    }
    ...
}
public class ExperimentalBitmapAnimationDrawableFactory implements DrawableFactory {

  ...
  
  @Override
  public AnimatedDrawable2 createDrawable(CloseableImage image) {
    return new AnimatedDrawable2(
        createAnimationBackend(
            ((CloseableAnimatedImage) image).getImageResult()));
  }

  private AnimationBackend createAnimationBackend(AnimatedImageResult animatedImageResult) {
    AnimatedDrawableBackend animatedDrawableBackend =
        createAnimatedDrawableBackend(animatedImageResult);

    BitmapFrameCache bitmapFrameCache = createBitmapFrameCache(animatedImageResult);//创建BitmapFrameCache
    BitmapFrameRenderer bitmapFrameRenderer =
        new AnimatedDrawableBackendFrameRenderer(bitmapFrameCache, animatedDrawableBackend);

    int numberOfFramesToPrefetch = mNumberOfFramesToPrepareSupplier.get();
    BitmapFramePreparationStrategy bitmapFramePreparationStrategy = null;
    BitmapFramePreparer bitmapFramePreparer = null;
    if (numberOfFramesToPrefetch > 0) {
      bitmapFramePreparationStrategy =
          new FixedNumberBitmapFramePreparationStrategy(numberOfFramesToPrefetch);
      bitmapFramePreparer = createBitmapFramePreparer(bitmapFrameRenderer);
    }

    BitmapAnimationBackend bitmapAnimationBackend = new BitmapAnimationBackend(
        mPlatformBitmapFactory,
        bitmapFrameCache,
        new AnimatedDrawableBackendAnimationInformation(animatedDrawableBackend),
        bitmapFrameRenderer,
        bitmapFramePreparationStrategy,
        bitmapFramePreparer);

    return AnimationBackendDelegateWithInactivityCheck.createForBackend(
        bitmapAnimationBackend,
        mMonotonicClock,
        mScheduledExecutorServiceForUiThread);
  }

    ...

    private BitmapFrameCache createBitmapFrameCache(AnimatedImageResult animatedImageResult) {
        switch (mCachingStrategySupplier.get()) {
          case CACHING_STRATEGY_FRESCO_CACHE:
          //创建FrescoFrameCache,并且设置可复用,即mEnableBitmapReusing为true
            return new FrescoFrameCache(createAnimatedFrameCache(animatedImageResult), true);         case CACHING_STRATEGY_FRESCO_CACHE_NO_REUSING:
            //创建FrescoFrameCache,并且设置不可复用,即mEnableBitmapReusing为false

            return new FrescoFrameCache(createAnimatedFrameCache(animatedImageResult), false);
          case CACHING_STRATEGY_KEEP_LAST_CACHE:
            return new KeepLastFrameCache();//保存上一帧的bitmap以复用
          case CACHING_STRATEGY_NO_CACHE:
          default:
            return new NoOpCache();//无缓存操作
        }
      }
  ...
}

FrescoFrameCache

在Fresco中的BitmapFrameCache默认的是的FrescoFrameCache,并且在KeepLastFrameCache,NoOpCache和FrescoFrameCache中,最复杂的就是FrescoFrameCache,把FrescoFrameCache分析清楚了,剩下的两个就会都明白了

public class FrescoFrameCache implements BitmapFrameCache {

//执行帧缓存的类
  private final AnimatedFrameCache mAnimatedFrameCache;
  private final boolean mEnableBitmapReusing;
  
    @GuardedBy("this")
  private final SparseArray> mPreparedPendingFrames;//存储准备的后面的帧

  @GuardedBy("this")
  @Nullable
  private CloseableReference mLastRenderedItem;//上一帧的图片

  public FrescoFrameCache(AnimatedFrameCache animatedFrameCache, boolean enableBitmapReusing) {
    mAnimatedFrameCache = animatedFrameCache;
    mEnableBitmapReusing = enableBitmapReusing;
    mPreparedPendingFrames = new SparseArray<>();
  }

//根据frameNumber获取对应帧的Bitmap
  @Nullable
  @Override
  public synchronized CloseableReference getCachedFrame(int frameNumber) {
    return convertToBitmapReferenceAndClose(mAnimatedFrameCache.get(frameNumber));
  }

//根据frameNumber获取对应后备帧
  @Nullable
  @Override
  public synchronized CloseableReference getFallbackFrame(int frameNumber) {
    return convertToBitmapReferenceAndClose(CloseableReference.cloneOrNull(mLastRenderedItem));
  }

//根据frameNumber获取对应帧的复用bitmap
  @Nullable
  @Override
  public synchronized CloseableReference getBitmapToReuseForFrame(
      int frameNumber,
      int width,
      int height) {
    if (!mEnableBitmapReusing) {//是否可复用,允许复用的话才会往下走
      return null;
    }
    return convertToBitmapReferenceAndClose(mAnimatedFrameCache.getForReuse());
  }

//内存缓存是否含有对应frameNumber帧的图片
  @Override
  public synchronized boolean contains(int frameNumber) {
    return mAnimatedFrameCache.contains(frameNumber);
  }

  @Override
  public synchronized int getSizeInBytes() {
    // This currently does not include the size of the animated frame cache
    return getBitmapSizeBytes(mLastRenderedItem) + getPreparedPendingFramesSizeBytes();
  }

//清除缓存,把对应的引用关闭,特别是准备的帧
  @Override
  public synchronized void clear() {
    CloseableReference.closeSafely(mLastRenderedItem);
    mLastRenderedItem = null;
    for (int i = 0; i < mPreparedPendingFrames.size(); i++) {
      CloseableReference.closeSafely(mPreparedPendingFrames.valueAt(i));
    }
    mPreparedPendingFrames.clear();
  }

//当对应帧在绘制后,执行响应的缓存操作
  @Override
  public synchronized void onFrameRendered(
      int frameNumber,
      CloseableReference bitmapReference,
      @BitmapAnimationBackend.FrameType int frameType) {
    Preconditions.checkNotNull(bitmapReference);

     //关闭存储在mPreparedPendingFrames的当前帧图片的引用,便于内存缓存可以回收
    removePreparedReference(frameNumber);
    //缓存对应帧
    CloseableReference closableReference = null;
    try {
      closableReference = createImageReference(bitmapReference);
      if (closableReference != null) {
        CloseableReference.closeSafely(mLastRenderedItem);
        mLastRenderedItem = mAnimatedFrameCache.cache(frameNumber, closableReference);
      }
    } finally {
      CloseableReference.closeSafely(closableReference);
    }
  }

//在提前准备帧的时候,把前面的几帧缓存起来,便于渲染时直接从内存中获取,提升性能
  @Override
  public synchronized void onFramePrepared(
      int frameNumber,
      CloseableReference bitmapReference,
      @BitmapAnimationBackend.FrameType int frameType) {
    Preconditions.checkNotNull(bitmapReference);
    CloseableReference closableReference = null;
    try {
      closableReference = createImageReference(bitmapReference);
      if (closableReference == null) {
        return;
      }
      CloseableReference newReference =
          mAnimatedFrameCache.cache(frameNumber, closableReference);
      if (CloseableReference.isValid(newReference)) {
        CloseableReference oldReference = mPreparedPendingFrames.get(frameNumber);
        CloseableReference.closeSafely(oldReference);
        // For performance reasons, we don't clone the reference and close the original one
        // 为了提升性能,防止对应的帧从内存中移除,所以存储在mPreparedPendingFrames中,保持对后面帧的引用
        mPreparedPendingFrames.put(frameNumber, newReference);
        ...
      }
    } finally {
      CloseableReference.closeSafely(closableReference);
    }
  }

  ...


  private synchronized int getPreparedPendingFramesSizeBytes() {
    int size = 0;
    for (int i = 0; i < mPreparedPendingFrames.size(); i++) {
      size += getBitmapSizeBytes(mPreparedPendingFrames.valueAt(i));
    }
    return size;
  }

  private synchronized void removePreparedReference(int frameNumber) {
    CloseableReference existingPendingReference =
        mPreparedPendingFrames.get(frameNumber);
    if (existingPendingReference != null) {
      mPreparedPendingFrames.delete(frameNumber);
      CloseableReference.closeSafely(existingPendingReference);
      ...
    }
  }

  //把对应的CloseableReference 转换成CloseableReference
  @VisibleForTesting
  @Nullable
  static CloseableReference convertToBitmapReferenceAndClose(
      final @Nullable CloseableReference closeableImage) {
    try {
      if (CloseableReference.isValid(closeableImage) &&
          closeableImage.get() instanceof CloseableStaticBitmap) {

        CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) closeableImage.get();
        if (closeableStaticBitmap != null) {
          return closeableStaticBitmap.cloneUnderlyingBitmapReference();
        }
      }
      return null;
    } finally {
      CloseableReference.closeSafely(closeableImage);
    }
  }

  ...

根据上面的代码,主要的工作是在AnimatedFrameCache中完成响应的缓存的操作,继续分析AnimatedFrameCache

public class AnimatedFrameCache {

//动图中对应帧在内存缓存中的CacheKey,根据帧索引和mImageCacheKey生成
  @VisibleForTesting
  static class FrameKey implements CacheKey {

    private final CacheKey mImageCacheKey;
    private final int mFrameIndex;

    public FrameKey(CacheKey imageCacheKey, int frameIndex) {
      mImageCacheKey = imageCacheKey;
      mFrameIndex = frameIndex;
    }

    ...
  }

  private final CacheKey mImageCacheKey;//动图的CacheKey
  private final CountingMemoryCache mBackingCache;//Fresco默认的内存缓存,就是Bitmapmemory,从外面传进来的
  private final CountingMemoryCache.EntryStateObserver mEntryStateObserver;////监听缓存的Entry的状态变化,Entry是CountingMemoryCache对CloseableReference 缓存value的包装
  @GuardedBy("this")
  private final LinkedHashSet mFreeItemsPool;//在内存缓存中已经没有对象引用的值,存储可以复用的帧的CacheKey

  public AnimatedFrameCache(
      CacheKey imageCacheKey,
      final CountingMemoryCache backingCache) {
    mImageCacheKey = imageCacheKey;
    mBackingCache = backingCache;
    mFreeItemsPool = new LinkedHashSet<>();
    mEntryStateObserver = new CountingMemoryCache.EntryStateObserver() {
      @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);
    }
  }

  //根据FrameKey往内存缓存中存储
  @Nullable
  public CloseableReference cache(
      int frameIndex,
      CloseableReference imageRef) {
    return mBackingCache.cache(keyFor(frameIndex), imageRef, mEntryStateObserver);
  }

  //获取对应帧的缓存
  @Nullable
  public CloseableReference get(int frameIndex) {
    return mBackingCache.get(keyFor(frameIndex));
  }

  //查询是否含有对应帧
  public boolean contains(int frameIndex) {
    return mBackingCache.contains(keyFor(frameIndex));
  }

  //获取可以复用的Bitmap,提高性能
  @Nullable
  public CloseableReference getForReuse() {
    while (true) {
      CacheKey key = popFirstFreeItemKey();
      if (key == null)  {
        return null;
      }
      CloseableReference imageRef = mBackingCache.reuse(key);
      if (imageRef != null) {
        return imageRef;
      }
    }
  }

//找到可以复用的CacheKey,然后从内存缓存中取出对应帧的图片
  @Nullable
  private synchronized CacheKey popFirstFreeItemKey() {
    CacheKey cacheKey = null;
    Iterator iterator = mFreeItemsPool.iterator();
    if (iterator.hasNext()) {
      cacheKey = iterator.next();
      iterator.remove();
    }
    return cacheKey;
  }

//根据索引生成FrameKey
  private FrameKey keyFor(int frameIndex)   {
    return new FrameKey(mImageCacheKey, frameIndex);
  }
}

根据上面的分析,缓存这一块的逻辑已经比较清晰了,就是在绘制的对应帧的时候,会传递给FrescoFrameCache,FrescoFrameCache会传递给AnimatedFrameCache,并且执行相应的缓存,最终的存储位置就是Fresco的bitmap缓存。还有一个很重要的逻辑时复用Bitmap,这块的逻辑是会在BitmapAnimationBackend::drawFrameOrFallback()中,复用的Bitmap其实就是在内存缓存中符合条件的没有其他对象引用的bitmap。

BitmapFramePreparer

在动图的渲染的过程中,绘制和缓存的操作说完了,下面还有一个比较重要的步骤,就是准备接下来的几帧,下面先找到准备的入口,就是在BitmapAnimationBackend::drawFrame()中,在drawFrameOrFallback 代码就不贴了,自己找一下
首先看一下BitmapFramePreparer创建的地方,在ExperimentalBitmapAnimationDrawableFactory

ExperimentalBitmapAnimationDrawableFactory 
 private AnimationBackend createAnimationBackend(AnimatedImageResult animatedImageResult) {
    ...
    
    int numberOfFramesToPrefetch = mNumberOfFramesToPrepareSupplier.get();//外面传进来的,默认是3帧
    BitmapFramePreparationStrategy bitmapFramePreparationStrategy = null;
    BitmapFramePreparer bitmapFramePreparer = null;
    if (numberOfFramesToPrefetch > 0) {//如果提前准备的帧数大于0,才会创建bitmapFramePreparationStrategy和BitmapFramePreparer
      bitmapFramePreparationStrategy =
          new FixedNumberBitmapFramePreparationStrategy(numberOfFramesToPrefetch);
      bitmapFramePreparer = createBitmapFramePreparer(bitmapFrameRenderer);
    }

   ...
  }
  
  private BitmapFramePreparer createBitmapFramePreparer(BitmapFrameRenderer bitmapFrameRenderer) {
    return new DefaultBitmapFramePreparer(
        mPlatformBitmapFactory,
        bitmapFrameRenderer,
        Bitmap.Config.ARGB_8888,
        mExecutorServiceForFramePreparing);
  }

上面设计到两个类,BitmapFramePreparationStrategy和BitmapFramePreparer,一个是策略,一个是具体操作,下面继续分析响应的类

public class FixedNumberBitmapFramePreparationStrategy implements BitmapFramePreparationStrategy {

  ...
  private static final int DEFAULT_FRAMES_TO_PREPARE = 3;

  private final int mFramesToPrepare;

  public FixedNumberBitmapFramePreparationStrategy() {
    this(DEFAULT_FRAMES_TO_PREPARE);
  }

  public FixedNumberBitmapFramePreparationStrategy(int framesToPrepare) {
    mFramesToPrepare = framesToPrepare;
  }

  @Override
  public void prepareFrames(
      BitmapFramePreparer bitmapFramePreparer,
      BitmapFrameCache bitmapFrameCache,
      AnimationBackend animationBackend,
      int lastDrawnFrameNumber) {
    for (int i = 1; i <= mFramesToPrepare; i++) {
      int nextFrameNumber = (lastDrawnFrameNumber + i) % animationBackend.getFrameCount();
      //调用bitmapFramePreparer.prepareFrame(),做提前准备帧的操作
      if (!bitmapFramePreparer.prepareFrame(
          bitmapFrameCache,
          animationBackend,
          nextFrameNumber)) {
        return;
      }
    }
  }
}

public class DefaultBitmapFramePreparer implements BitmapFramePreparer {
    ...
    
    @Override
  public boolean prepareFrame(
      BitmapFrameCache bitmapFrameCache,
      AnimationBackend animationBackend,
      int frameNumber) {
   ...
      Runnable frameDecodeRunnable = new FrameDecodeRunnable(
          animationBackend,
          bitmapFrameCache,
          frameNumber,
          frameId);
      mPendingFrameDecodeJobs.put(frameId, frameDecodeRunnable);
      //执行frameDecodeRunnable
      mExecutorService.execute(frameDecodeRunnable);
    }
    return true;
  }
  ...
 
}


private class FrameDecodeRunnable implements Runnable {

    private final BitmapFrameCache mBitmapFrameCache;
    private final AnimationBackend mAnimationBackend;
    private final int mFrameNumber;
    private final int mHashCode;

    public FrameDecodeRunnable(
        AnimationBackend animationBackend,
        BitmapFrameCache bitmapFrameCache,
        int frameNumber,
        int hashCode) {
      mAnimationBackend = animationBackend;
      mBitmapFrameCache = bitmapFrameCache;
      mFrameNumber = frameNumber;
      mHashCode = hashCode;
    }

    @Override
    public void run() {
      try {
        ...

        // 准备帧
        if (prepareFrameAndCache(mFrameNumber, BitmapAnimationBackend.FRAME_TYPE_REUSED)) {
          FLog.v(TAG, "Prepared frame frame %d.", mFrameNumber);
        } else {
          FLog.e(TAG, "Could not prepare frame %d.", mFrameNumber);
        }
      } finally {
        synchronized (mPendingFrameDecodeJobs) {
          mPendingFrameDecodeJobs.remove(mHashCode);
        }
      }
    }

//这里跟BitmapAnimationBackend::drawFramorFallback()逻辑类似,准备帧并且缓存,跟BitmapAnimationBackend::drawBitmapAndCache()类似,就不再分析了
    private boolean prepareFrameAndCache(
        int frameNumber,
        @BitmapAnimationBackend.FrameType int frameType) {
      CloseableReference bitmapReference = null;
      boolean created;
      int nextFrameType;

      try {
        switch (frameType) {
          case BitmapAnimationBackend.FRAME_TYPE_REUSED:
            bitmapReference =
                mBitmapFrameCache.getBitmapToReuseForFrame(
                    frameNumber,
                    mAnimationBackend.getIntrinsicWidth(),
                    mAnimationBackend.getIntrinsicHeight());
            nextFrameType = BitmapAnimationBackend.FRAME_TYPE_CREATED;
            break;

          case BitmapAnimationBackend.FRAME_TYPE_CREATED:
            try {
              bitmapReference =
                  mPlatformBitmapFactory.createBitmap(
                      mAnimationBackend.getIntrinsicWidth(),
                      mAnimationBackend.getIntrinsicHeight(),
                      mBitmapConfig);
            } catch (RuntimeException e) {
             ...
              return false;
            }
            nextFrameType = BitmapAnimationBackend.FRAME_TYPE_UNKNOWN;
            break;
          default:
            return false;
        }
        //尝试渲染并且缓存,这里的渲染不会帧的绘制,只是把bitmapReference对应的Bitmap的像素信息,变成之后的几帧,并且缓存起来
        created = renderFrameAndCache(frameNumber, bitmapReference, frameType);
      } finally {
        CloseableReference.closeSafely(bitmapReference);
      }

      if (created || nextFrameType == BitmapAnimationBackend.FRAME_TYPE_UNKNOWN) {
        return created;
      } else {
        return prepareFrameAndCache(frameNumber, nextFrameType);
      }
    }

    private boolean renderFrameAndCache(
        int frameNumber,
        CloseableReference bitmapReference,
        @BitmapAnimationBackend.FrameType int frameType) {
       ...
      //改变像素信息,
      if (!mBitmapFrameRenderer.renderFrame(frameNumber, bitmapReference.get())) {
        return false;
      }
      //缓存
      synchronized (mPendingFrameDecodeJobs) {
        mBitmapFrameCache.onFramePrepared(mFrameNumber, bitmapReference, frameType);
      }
      return true;
    }
  }
}

提前准备帧的逻辑也清楚了,到这里Fresco中动图的加载逻辑也分析清楚了

BitmapFrameRenderer::
...

private AnimatedImageCompositor mAnimatedImageCompositor;

...

@Override
  public boolean renderFrame(int frameNumber, Bitmap targetBitmap) {
    try {
      mAnimatedImageCompositor.renderFrame(frameNumber, targetBitmap);
    } catch (IllegalStateException exception) {
      return false;
    }
    return true;
  }
...

AnimatedImageCompositor::


  public void renderFrame(int frameNumber, Bitmap bitmap) {
    Canvas canvas = new Canvas(bitmap);
    canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SRC);

    // If blending is required, prepare the canvas with the nearest cached frame.
    int nextIndex;
    if (!isKeyFrame(frameNumber)) {
      // Blending is required. nextIndex points to the next index to render onto the canvas.
      nextIndex = prepareCanvasWithClosestCachedFrame(frameNumber - 1, canvas);
    } else {
      // Blending isn't required. Start at the frame we're trying to render.
      nextIndex = frameNumber;
    }

    // 这里主要涉及到透明度的混合问题
    for (int index = nextIndex; index < frameNumber; index++) {
      AnimatedDrawableFrameInfo frameInfo = mAnimatedDrawableBackend.getFrameInfo(index);
      DisposalMethod disposalMethod = frameInfo.disposalMethod;
      if (disposalMethod == DisposalMethod.DISPOSE_TO_PREVIOUS) {
        continue;
      }
      if (frameInfo.blendOperation == BlendOperation.NO_BLEND) {
        disposeToBackground(canvas, frameInfo);
      }
      mAnimatedDrawableBackend.renderFrame(index, canvas);
      mCallback.onIntermediateResult(index, bitmap);
      if (disposalMethod == DisposalMethod.DISPOSE_TO_BACKGROUND) {
        disposeToBackground(canvas, frameInfo);
      }
    }

    AnimatedDrawableFrameInfo frameInfo = mAnimatedDrawableBackend.getFrameInfo(frameNumber);
    if (frameInfo.blendOperation == BlendOperation.NO_BLEND) {
      disposeToBackground(canvas, frameInfo);
    }
    //最终,绘制当前帧
    mAnimatedDrawableBackend.renderFrame(frameNumber, canvas);
  }

你可能感兴趣的:(Fresco Gif加载解析)