Skip to content Skip to sidebar Skip to footer

Using Facebook's Fresco To Load A Bitmap

I'm trying to replace Picasso in my android app with Fresco. However I am unsure of how to simply load a bitmap using Fresco. With Picasso I would just do the following. Bitmap p

Solution 1:

As Fresco said:

If your request to the pipeline is for a decoded image - an Android Bitmap, you can take advantage of our easier-to-use BaseBitmapDataSubscriber:

dataSource.subscribe(new BaseBitmapDataSubscriber() {
    @Override
    public void onNewResultImpl(@Nullable Bitmap bitmap) {
       // You can use the bitmap in only limited ways// No need to do any cleanup.
    }

    @Override
    public void onFailureImpl(DataSource dataSource) {
      // No cleanup required here.
    }
  },
  executor);

You can not assign the bitmap to any variable not in the scope of the onNewResultImpl method.

http://frescolib.org/docs/datasources-datasubscribers.html#_

My code :

publicvoidsetDataSubscriber(Context context, Uri uri, int width, int height){
    DataSubscriberdataSubscriber=newBaseDataSubscriber<CloseableReference<CloseableBitmap>>() {
        @OverridepublicvoidonNewResultImpl(
                DataSource<CloseableReference<CloseableBitmap>> dataSource) {
            if (!dataSource.isFinished()) {
                return;
            }
            CloseableReference<CloseableBitmap> imageReference = dataSource.getResult();
            if (imageReference != null) {
                final CloseableReference<CloseableBitmap> closeableReference = imageReference.clone();
                try {
                    CloseableBitmapcloseableBitmap= closeableReference.get();
                    Bitmapbitmap= closeableBitmap.getUnderlyingBitmap();
                    if(bitmap != null && !bitmap.isRecycled()) {
                        //you can use bitmap here
                    }
                } finally {
                    imageReference.close();
                    closeableReference.close();
                }
            }
        }
        @OverridepublicvoidonFailureImpl(DataSource dataSource) {
            Throwablethrowable= dataSource.getFailureCause();
            // handle failure
        }
    };
    getBitmap(context, uri, width, height, dataSubscriber);
}

/**
 *
 * @param context
 * @param uri
 * @param width          
 * @param height         
 * @param dataSubscriber
 */publicvoidgetBitmap(Context context, Uri uri, int width, int height, DataSubscriber dataSubscriber){
    ImagePipelineimagePipeline= Fresco.getImagePipeline();
    ImageRequestBuilderbuilder= ImageRequestBuilder.newBuilderWithSource(uri);
    if(width > 0 && height > 0){
        builder.setResizeOptions(newResizeOptions(width, height));
    }
    ImageRequestrequest= builder.build();
    DataSource<CloseableReference<CloseableImage>>
            dataSource = imagePipeline.fetchDecodedImage(request, context);
    dataSource.subscribe(dataSubscriber, UiThreadExecutorService.getInstance());
}

Solution 2:

You would use Fresco's CacheKey directly for this:

publicclassDownloadVideoThumbnailextendsAsyncTask<String, Void, Bitmap> {
private ImageView bmImage;
private Bitmap bitmapVideo;
private Context context;

publicDownloadVideoThumbnail(Context context, ImageView bmImage) {
    this.bmImage = (ImageView) bmImage;
    this.context = context;
}

protected Bitmap doInBackground(String... urls) {

    StringurlStr= urls[0];
    if (readFromCacheSync(urlStr) == null) {
        try {
            //Your method call here
            bitmapVideo = retriveVideoFrameFromVideo(urlStr);

        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    } else {
        bitmapVideo = readFromCacheSync(urlStr);
    }
    returnnull;
}

protectedvoidonPostExecute(Bitmap result) {
    if (bitmapVideo != null) {
        //Load your bitmap here
        bmImage.setImageBitmap(bitmapVideo);
        bmImage.setScaleType(ImageView.ScaleType.CENTER_CROP);
    }
}


publicvoidcacheBitmap(Bitmap bitmap, String url) {
    try {
        CacheKeycacheKey=newSimpleCacheKey(url);
        ByteArrayOutputStreamstream=newByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
        finalbyte[] byteArray = stream.toByteArray();
        Fresco.getImagePipelineFactory().getMainFileCache().insert(cacheKey, newWriterCallback() {
            @Overridepublicvoidwrite(OutputStream outputStream)throws IOException {
                outputStream.write(byteArray);
            }
        });
    } catch (IOException cacheWriteException) {

    }
}

publicstatic Bitmap readFromCacheSync(String imageUrl) {
    CacheKeycacheKey= DefaultCacheKeyFactory.getInstance().getEncodedCacheKey(ImageRequest.fromUri(imageUrl), null);
    StagingAreastagingArea= StagingArea.getInstance();
    EncodedImageencodedImage= stagingArea.get(cacheKey);
    if (encodedImage != null) {

        return BitmapFactory.decodeStream(encodedImage.getInputStream());
    }

    try {
        return BitmapFactory.decodeStream(readFromDiskCache(cacheKey));
    } catch (Exception e) {
        returnnull;
    }
}


privatestatic InputStream readFromDiskCache(final CacheKey key)throws IOException {
    try {
        FileCachefileCache= ImagePipelineFactory.getInstance().getMainFileCache();
        finalBinaryResourcediskCacheResource= fileCache.getResource(key);
        if (diskCacheResource == null) {
            FLog.v(TAG, "Disk cache miss for %s", key.toString());
            returnnull;
        }
        PooledByteBuffer byteBuffer;
        finalInputStreamis= diskCacheResource.openStream();
        FLog.v(TAG, "Successful read from disk cache for %s", key.toString());
        return is;
    } catch (IOException ioe) {
        returnnull;
    }
}

public Bitmap retriveVideoFrameFromVideo(String videoPath)throws Throwable {

    Bitmapbitmap=null;
    MediaMetadataRetrievermediaMetadataRetriever=null;
    try {
        mediaMetadataRetriever = newMediaMetadataRetriever();
        if (Build.VERSION.SDK_INT >= 14)
            mediaMetadataRetriever.setDataSource(videoPath, newHashMap<String, String>());
        else
            mediaMetadataRetriever.setDataSource(videoPath);
        bitmap = mediaMetadataRetriever.getFrameAtTime();
        if (bitmap != null) {
            ByteArrayOutputStreamstream=newByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 70, stream);
            cacheBitmap(bitmap, videoPath);
        }
    } catch (Exception e) {
        e.printStackTrace();
        thrownewThrowable(
                "Exception in retriveVideoFrameFromVideo(String videoPath)"
                        + e.getMessage());

    } finally {
        if (mediaMetadataRetriever != null) {
            mediaMetadataRetriever.release();
        }
    }
    return bitmap;
}
}

Solution 3:

You would use Fresco's image pipeline directly for this:

http://frescolib.org/docs/using-image-pipeline.html

Though if you don't mind my asking - what is the motivation here? Why do you need the Bitmap itself?

Solution 4:

Starting from this answer I created a quick implementation that uses Kotlin extensions and RxJava to get a ClosableBitmap from an ImageRequest:

fun ImageRequest.getBitmap(context: Context): Maybe<CloseableReference<CloseableBitmap>> {
    val dataSource = Fresco.getImagePipeline().fetchDecodedImage(this, context)
    return Maybe.create { emitter ->
        dataSource.subscribe(
            object : BaseDataSubscriber<CloseableReference<CloseableImage>>() {
                overridefunonFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
                    emitter.onComplete()
                }

                overridefunonNewResultImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
                    if (!dataSource.isFinished) {
                        return
                    }

                    dataSource.result
                        ?.takeIf { it.get() is CloseableBitmap }
                        ?.let {
                            @Suppress("UNCHECKED_CAST")
                            emitter.onSuccess(it as CloseableReference<CloseableBitmap>)
                        }

                    emitter.onComplete()
                }
            },
            DefaultExecutorSupplier(1).forBackgroundTasks()
        )
    }
}

Since by contract it is required to close the reference once the bitmap has been used, I created this util function:

/**
 * The bitmap passed into [block] is only valid during the execution of the method.
 */fun<T> CloseableReference<CloseableBitmap>.useBitmap(block: (Bitmap?) -> T): T? {
    returntry {
        this.get()?.underlyingBitmap?.let { block(it) }
    } finally {
        CloseableReference.closeSafely(this)
    }
}

Solution 5:

I found this solution using Kotlin's coroutines:

suspendfungetBitmapFromUri(imageUri: Uri): Bitmap = withContext(Dispatchers.Default) {
    val imageRequest = ImageRequestBuilder.newBuilderWithSource(imageUri).build()
    val dataSource = Fresco.getImagePipeline().fetchDecodedImage(imageRequest, this)
    val result = DataSources.waitForFinalResult(dataSource) as CloseableReference<CloseableBitmap>

    val bitmap = result.get().underlyingBitmap

    CloseableReference.closeSafely(result)
    dataSource.close()

    return@withContext bitmap
}

Post a Comment for "Using Facebook's Fresco To Load A Bitmap"