Using Facebook's Fresco To Load A Bitmap
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"