Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FetchDecodedImage return recycled bitmap #717

Closed
karun2189 opened this issue Oct 30, 2015 · 17 comments
Closed

FetchDecodedImage return recycled bitmap #717

karun2189 opened this issue Oct 30, 2015 · 17 comments
Labels

Comments

@karun2189
Copy link

@karun2189 karun2189 commented Oct 30, 2015

I am getting "Canvas: trying to use a recycled bitmap" error. If i am get bitmap from cache by using below code

ImagePipeline imagePipeline = Fresco.getImagePipeline();
        ImageRequest imageRequest = ImageRequestBuilder
                .newBuilderWithSource(Uri.fromFile(new File(url)))
                .build();

        DataSource<CloseableReference<CloseableImage>>
                dataSource = imagePipeline.fetchDecodedImage(imageRequest, mContext);
        dataSource.subscribe(new BaseBitmapDataSubscriber() {

                                 @Override
                                 public void onNewResultImpl(@Nullable Bitmap bitmap) {
                                     if (cacheListener != null) {
                                         cacheListener.onAvailableBitmap(bitmap);
                                     }
                                 }

                                 @Override
                                 public void onFailureImpl(DataSource dataSource) {
                                     if (cacheListener != null) {
                                         cacheListener.onAvailableBitmap(null);
                                     }
                                 }
                             },
                CallerThreadExecutor.getInstance());

Why i am getting this error ? I am getting frequently..
Thanks

@massimocarli

This comment has been minimized.

Copy link
Contributor

@massimocarli massimocarli commented Oct 30, 2015

As documentation says the Bitmap into the onNewResultImpl() method is only guaranteed to be around for the lifespan of the method. This means you have to consume the image into that method. Probably you're keeping the image around. Try to use a BaseDataSubscriber instead.

* The bitmap provided to this method is only guaranteed to be around for the lifespan of the

@karun2189

This comment has been minimized.

Copy link
Author

@karun2189 karun2189 commented Oct 30, 2015

I am getting same exception if i am using below code

ImagePipeline imagePipeline = Fresco.getImagePipeline();
        ImageRequest imageRequest = ImageRequestBuilder
                .newBuilderWithSource(Uri.fromFile(new File(url)))
                .build();

        DataSource<CloseableReference<CloseableImage>>
                dataSource = imagePipeline.fetchDecodedImage(imageRequest, mContext);
        dataSource.subscribe(new BaseDataSubscriber<CloseableReference<CloseableImage>>() {
            @Override
            protected void onNewResultImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
                if (!dataSource.isFinished()) {
                    return;
                }

                CloseableReference<CloseableImage> closeableImageRef = dataSource.getResult();
                Bitmap bitmap = null;
                if (closeableImageRef != null &&
                        closeableImageRef.get() instanceof CloseableBitmap) {
                    bitmap = ((CloseableBitmap) closeableImageRef.get()).getUnderlyingBitmap();
                }

                if(cacheListener != null){
                    cacheListener.onAvailableBitmap(bitmap);
                }
            }

            @Override
            protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
                if(cacheListener != null){
                    cacheListener.onAvailableBitmap(null);
                }
            }
        }, CallerThreadExecutor.getInstance());
@massimocarli

This comment has been minimized.

Copy link
Contributor

@massimocarli massimocarli commented Oct 30, 2015

How are you using the image into the Canvas? Can you provide a snippet please?
Thanks

@karun2189

This comment has been minimized.

Copy link
Author

@karun2189 karun2189 commented Oct 30, 2015

Bitmap = "this bitmap i am getting from cache."
Drawable d = new BitmapDrawable(getResources(), bitmap);
CustomImageSpan imageSpan = new CustomImageSpan(d,ImageSpan.ALIGN_BASELINE);
editable.setSpan(imageSpan, (start), (end), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

Here set span will automatically call invalidate at that time i am getting the exception.

@massimocarli

This comment has been minimized.

Copy link
Contributor

@massimocarli massimocarli commented Oct 30, 2015

At some stage there's a call to Bitmap recycle() probably in CustomImageSpan. Could you check if the Bitmap in the onNewResultImpl() has isRecycled() returning false?

Thanks

@karun2189

This comment has been minimized.

Copy link
Author

@karun2189 karun2189 commented Oct 30, 2015

We are not calling the recycle method. If we are get directly bitmap from path it will work fine without using cache if we are use cache the it will show the exception

@massimocarli

This comment has been minimized.

Copy link
Contributor

@massimocarli massimocarli commented Oct 30, 2015

Do you mean ImagePipeline caches or another cache implementation?

@karun2189

This comment has been minimized.

Copy link
Author

@karun2189 karun2189 commented Oct 30, 2015

ImagePipeline caches

@karun2189

This comment has been minimized.

Copy link
Author

@karun2189 karun2189 commented Nov 2, 2015

What details you need ? The exception is occur frequently.....If you give solution its great helpful for me

@tyronen

This comment has been minimized.

Copy link
Contributor

@tyronen tyronen commented Nov 3, 2015

Your code above is wrong. You are taking the Bitmap out of the CloseableReference and passing it to the rest of your app. When the reference count goes to zero, your Bitmap will be recycled without warning.

You should instead pass the CloseableReference<Bitmap> to the rest of your app, and hold a reference to it. When you are done with the Bitmap, then call close().

@tyronen tyronen closed this Nov 3, 2015
@karun2189

This comment has been minimized.

Copy link
Author

@karun2189 karun2189 commented Nov 6, 2015

@tyronen If i close the CloseableReference after setting the bitmap again i am getting same exception ? Can you explain me why this occur what i want to do

@tyronen

This comment has been minimized.

Copy link
Contributor

@tyronen tyronen commented Nov 6, 2015

That sounds like you are closing the reference too early. Once you have called close, you should never again pass that bitmap to any draw method.

@happyjosh

This comment has been minimized.

Copy link

@happyjosh happyjosh commented May 5, 2017

@massimocarli @tyronen @karun2189 I am also having same issues when I use CustomImageSpan。So,When should I close the reference?

@oprisnik

This comment has been minimized.

Copy link
Contributor

@oprisnik oprisnik commented May 5, 2017

You should close the reference when nothing holds on to the bitmap and when the bitmap will never be rendered again.

@happyjosh

This comment has been minimized.

Copy link

@happyjosh happyjosh commented May 8, 2017

Now I create a new bitmap by old from fresco to resolve the problem.Because I can not exactly judge whether be rendered.

@ThugKd

This comment has been minimized.

Copy link

@ThugKd ThugKd commented Jun 13, 2019

I am getting same exception if i am using below code

public static void setImageUrl(final ImageView view, String url) {
        final ImageRequest request = ImageRequestBuilder
                .newBuilderWithSource(Uri.parse(url))
                .build();
        Fresco.getImagePipeline()
                .fetchDecodedImage(request, view.getContext().getApplicationContext())
                .subscribe(new BaseBitmapDataSubscriber() {
                    @Override
                    protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {

                    }

                    @Override
                    protected void onNewResultImpl(Bitmap bitmap) {
                        if (bitmap != null) {
                            view.setImageBitmap(bitmap);
                        }
                    }
                }, UiExecutor);
    }
@oprisnik

This comment has been minimized.

Copy link
Contributor

@oprisnik oprisnik commented Jun 13, 2019

See the first comment. The bitmap will be recycled once onNewResultImpl is done. You have to use a BaseBitmapReferenceDataSubscriber instead and properly manage the lifecycle of the reference.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
6 participants
You can’t perform that action at this time.