Using Facebook's Fresco to load a bitmap

后端 未结 5 1034
自闭症患者
自闭症患者 2020-12-06 01:59

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 foll

相关标签:
5条回答
  • 2020-12-06 02:07

    You would use Fresco's CacheKey directly for this:

    public class DownloadVideoThumbnail extends AsyncTask<String, Void, Bitmap> {
    private ImageView bmImage;
    private Bitmap bitmapVideo;
    private Context context;
    
    public DownloadVideoThumbnail(Context context, ImageView bmImage) {
        this.bmImage = (ImageView) bmImage;
        this.context = context;
    }
    
    protected Bitmap doInBackground(String... urls) {
    
        String urlStr = urls[0];
        if (readFromCacheSync(urlStr) == null) {
            try {
                //Your method call here
                bitmapVideo = retriveVideoFrameFromVideo(urlStr);
    
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        } else {
            bitmapVideo = readFromCacheSync(urlStr);
        }
        return null;
    }
    
    protected void onPostExecute(Bitmap result) {
        if (bitmapVideo != null) {
            //Load your bitmap here
            bmImage.setImageBitmap(bitmapVideo);
            bmImage.setScaleType(ImageView.ScaleType.CENTER_CROP);
        }
    }
    
    
    public void cacheBitmap(Bitmap bitmap, String url) {
        try {
            CacheKey cacheKey = new SimpleCacheKey(url);
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
            final byte[] byteArray = stream.toByteArray();
            Fresco.getImagePipelineFactory().getMainFileCache().insert(cacheKey, new WriterCallback() {
                @Override
                public void write(OutputStream outputStream) throws IOException {
                    outputStream.write(byteArray);
                }
            });
        } catch (IOException cacheWriteException) {
    
        }
    }
    
    public static Bitmap readFromCacheSync(String imageUrl) {
        CacheKey cacheKey = DefaultCacheKeyFactory.getInstance().getEncodedCacheKey(ImageRequest.fromUri(imageUrl), null);
        StagingArea stagingArea = StagingArea.getInstance();
        EncodedImage encodedImage = stagingArea.get(cacheKey);
        if (encodedImage != null) {
    
            return BitmapFactory.decodeStream(encodedImage.getInputStream());
        }
    
        try {
            return BitmapFactory.decodeStream(readFromDiskCache(cacheKey));
        } catch (Exception e) {
            return null;
        }
    }
    
    
    private static InputStream readFromDiskCache(final CacheKey key) throws IOException {
        try {
            FileCache fileCache = ImagePipelineFactory.getInstance().getMainFileCache();
            final BinaryResource diskCacheResource = fileCache.getResource(key);
            if (diskCacheResource == null) {
                FLog.v(TAG, "Disk cache miss for %s", key.toString());
                return null;
            }
            PooledByteBuffer byteBuffer;
            final InputStream is = diskCacheResource.openStream();
            FLog.v(TAG, "Successful read from disk cache for %s", key.toString());
            return is;
        } catch (IOException ioe) {
            return null;
        }
    }
    
    public Bitmap retriveVideoFrameFromVideo(String videoPath) throws Throwable {
    
        Bitmap bitmap = null;
        MediaMetadataRetriever mediaMetadataRetriever = null;
        try {
            mediaMetadataRetriever = new MediaMetadataRetriever();
            if (Build.VERSION.SDK_INT >= 14)
                mediaMetadataRetriever.setDataSource(videoPath, new HashMap<String, String>());
            else
                mediaMetadataRetriever.setDataSource(videoPath);
            bitmap = mediaMetadataRetriever.getFrameAtTime();
            if (bitmap != null) {
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.JPEG, 70, stream);
                cacheBitmap(bitmap, videoPath);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new Throwable(
                    "Exception in retriveVideoFrameFromVideo(String videoPath)"
                            + e.getMessage());
    
        } finally {
            if (mediaMetadataRetriever != null) {
                mediaMetadataRetriever.release();
            }
        }
        return bitmap;
    }
    }
    
    0 讨论(0)
  • 2020-12-06 02:08

    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?

    0 讨论(0)
  • 2020-12-06 02:15

    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>>() {
                    override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
                        emitter.onComplete()
                    }
    
                    override fun onNewResultImpl(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? {
        return try {
            this.get()?.underlyingBitmap?.let { block(it) }
        } finally {
            CloseableReference.closeSafely(this)
        }
    }
    
    0 讨论(0)
  • 2020-12-06 02:23

    I found this solution using Kotlin's coroutines:

    suspend fun getBitmapFromUri(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
    }
    
    0 讨论(0)
  • 2020-12-06 02:24

    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 :

    public void setDataSubscriber(Context context, Uri uri, int width, int height){
        DataSubscriber dataSubscriber = new BaseDataSubscriber<CloseableReference<CloseableBitmap>>() {
            @Override
            public void onNewResultImpl(
                    DataSource<CloseableReference<CloseableBitmap>> dataSource) {
                if (!dataSource.isFinished()) {
                    return;
                }
                CloseableReference<CloseableBitmap> imageReference = dataSource.getResult();
                if (imageReference != null) {
                    final CloseableReference<CloseableBitmap> closeableReference = imageReference.clone();
                    try {
                        CloseableBitmap closeableBitmap = closeableReference.get();
                        Bitmap bitmap  = closeableBitmap.getUnderlyingBitmap();
                        if(bitmap != null && !bitmap.isRecycled()) {
                            //you can use bitmap here
                        }
                    } finally {
                        imageReference.close();
                        closeableReference.close();
                    }
                }
            }
            @Override
            public void onFailureImpl(DataSource dataSource) {
                Throwable throwable = dataSource.getFailureCause();
                // handle failure
            }
        };
        getBitmap(context, uri, width, height, dataSubscriber);
    }
    
    /**
     *
     * @param context
     * @param uri
     * @param width          
     * @param height         
     * @param dataSubscriber
     */
    public void getBitmap(Context context, Uri uri, int width, int height, DataSubscriber dataSubscriber){
        ImagePipeline imagePipeline = Fresco.getImagePipeline();
        ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);
        if(width > 0 && height > 0){
            builder.setResizeOptions(new ResizeOptions(width, height));
        }
        ImageRequest request = builder.build();
        DataSource<CloseableReference<CloseableImage>>
                dataSource = imagePipeline.fetchDecodedImage(request, context);
        dataSource.subscribe(dataSubscriber, UiThreadExecutorService.getInstance());
    }
    
    0 讨论(0)
提交回复
热议问题