Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fresco: Use current image displayed in Drawee as a placeholder for next request

I play multiple images sequentially on the same SimpleDraweeView, the issue is that when submitting a new imageURI request, theSimpleDrweeView will remove the current displayed image and replace it with nothing until the URI is downloaded. So it will leave gaps in the playing sequence ( you could think of what I'm trying to do is cartoon animation using local photos). What I would like for the SimpleDrweeView to leave the current image as is until the new one is downloaded and then just swap it when it's ready.

I tried using the low-res/high-res scheme from this ticket to put the old uri as a placeholder but that didn't work (had the same effect as before).

This is what I have now:

 SimpleDraweeView draweeView = (SimpleDraweeView) findViewById(R.id.my_image_view);

 draweeView.setImageURI(uri /* local image */); 

And this is what I tried so far (didn't work):

                SimpleDraweeView draweeView = (SimpleDraweeView) findViewById(R.id.my_image_view);

            Uri lowResUri, highResUri;
            DraweeController controller = Fresco.newDraweeControllerBuilder().setTapToRetryEnabled(true)
                    .setLowResImageRequest(ImageRequest.fromUri((Uri) draweeView.getTag())) /*naive way to test the low/high res feature*/
                    .setImageRequest(ImageRequest.fromUri(uri))
                    .setOldController(draweeView.getController())
                    .build();
            draweeView.setTag(uri);
            draweeView.setController(controller); 
like image 590
Jimmy Avatar asked Nov 26 '15 23:11

Jimmy


1 Answers

I am part of the Fresco team and may be able to help. It is strange that you experience the same issue with low-res/high-res combination. If the image is currently displayed, it means it should be in the bitmap memory cache, which in turn means that it should be able to load immediately when set as a low-res image the next time you are switching to the next frame. Are you sure that you are setting the correct uri as low-res image? (Uri) draweeView.getTag() looks kind of suspicious. I would double check that part.

If the uri is indeed correct, but the image is not in the bitmap cache anymore, it would be worth investigating why the image that is visible is not cached anymore, as we have explicit logic in place that should prevent evicting visible images. See how to track this with verbose logging here.

If all of the above fails, third options is to actually implement your own DataSource. I can help with that, but this might be somewhat involving. The basic idea is to implement a DataSource that wraps another DataSource that actually provides the image. Then you could do something like this:

// keep this instance somewhere
mMyDataSourceSupplier = new MyDataSourceSupplier();

// build controller by specifying your custom datasource supplier instead of specifying any URIs.
Fresco.newDraweeControllerBuilder()
  .setDataSourceSupplier(mMyDataSourceSupplier)
  .build()

// later, when you need to change the image do
mMyDataSourceSupplier.setUri(nextUri);

// this is just an outline
class MyDataSourceSupplier implements Supplier<DataSource<CloseableReference<CloseableImage>>> {

  private Uri mCurrentUri;
  private DataSource<CloseableReference<CloseableImage>> mCurrentDataSource;

  public void setUri(Uri uri) {
    mCurrentUri = uri;
    if (mCurrentDatasource != null) {
      mCurrentDataSource.setUri(uri);
    }
  }

  @Override
  public DataSource<CloseableReference<CloseableImage>> get() {
    mCurrentDataSource = new MyDataSource();
    mCurrentDataSource.setUri(uri);
    return mCurrentDataSource;
  }

  private class MyDataSource extends AbstractDataSource<CloseableReference<CloseableImage>> {
    private DataSource mUnderlyingDataSource;

    @Override
    protected void closeResult(@Nullable CloseableReference<CloseableImage> result) {
      CloseableReference.closeSafely(result);
    }

    @Override
    @Nullable
    public CloseableReference<CloseableImage> getResult() {
      return CloseableReference.cloneOrNull(super.getResult());
    }


    @Override
    public boolean close() {
      if (mUnderlyingDataSource != null) {
        mUnderlyingDataSource.close();
        mUnderlyingDataSource = null;
      }
      return super.close();
    }

    public void setUri(Uri uri) {
      if (mUnderlyingDataSource != null) {
        mUnderlyingDataSource.close();
        mUnderlyingDataSource = null;
      }
      if (uri != null && !isClosed()) {
        mUnderlyingDataSource = Fresco.getImagePipeline().fetchDecodedImage(ImageRequest.fromUri(uri), null);
        mUnderlyingDataSource.subscribe(new BaseDataSubscriber {
          @Override
          protected void onNewResultImpl(DataSource<List<CloseableReference<CloseableImage>>> dataSource) {
            MyDataSource.super.setResult(dataSource.getResult(), false);
          }
        });
      }
    }
  }
}
like image 94
plamenko Avatar answered Oct 10 '22 15:10

plamenko