Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Cannot draw recycled bitmaps" exception with Picasso

I've music player app which interacts with RemoteControlClient. I need to load album cover image to display it in lock screen widget. I try to use Piccasso to achieve this. I've written the folowing code:

private final Target artworkTarget = new Target() {
    @Override
    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) {
        remoteControlClient.editMetadata(false).putBitmap(RemoteControlClientCompat.MetadataEditorCompat.METADATA_KEY_ARTWORK,
                bitmap).apply();
    }

    @Override
    public void onBitmapFailed(Drawable drawable) {
        Log.e(Constants.LOG_TAG, "Artwork loading failed");
    }

    @Override
    public void onPrepareLoad(Drawable drawable) {
    }
};

...

private void playNextSong(int songPosition) {
    ...

    String artworkUrl = Constants.Urls.BASE_ARTWORK_URL + currentSong.getArtworkId();
    Picasso.with(this).load(artworkUrl).skipMemoryCache().into(artworkTarget);
    // Update the remote controls
    remoteControlClient.editMetadata(true)
                .putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, currentSong.getArtist().getName())
                .putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, currentSong.getAlbum().getName())
                .putString(MediaMetadataRetriever.METADATA_KEY_TITLE, currentSong.getName())
                .apply();

   ...
   }

But sometimes I get exception:

    ERROR/AndroidRuntime(31121): FATAL EXCEPTION: main
    java.lang.IllegalArgumentException: Cannot draw recycled bitmaps
    at android.view.GLES20Canvas.drawBitmap(GLES20Canvas.java:772)
    at android.view.GLES20RecordingCanvas.drawBitmap(GLES20RecordingCanvas.java:105)
    at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:440)
    at com.squareup.picasso.PicassoDrawable.draw(PicassoDrawable.java:96)
    at android.widget.ImageView.onDraw(ImageView.java:1025)
    at android.view.View.draw(View.java:13944)
    at android.view.View.getDisplayList(View.java:12838)
    at android.view.View.getDisplayList(View.java:12880)
    at android.view.View.draw(View.java:13657)
    at android.view.ViewGroup.drawChild(ViewGroup.java:3083)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2920)
    at android.view.View.getDisplayList(View.java:12833)
    at android.view.View.getDisplayList(View.java:12880)
    at android.view.View.draw(View.java:13657)
    at android.view.ViewGroup.drawChild(ViewGroup.java:3083)
    at android.widget.ListView.drawChild(ListView.java:3331)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2920)
    at android.widget.AbsListView.dispatchDraw(AbsListView.java:2357)
    at android.widget.ListView.dispatchDraw(ListView.java:3326)
    at android.view.View.draw(View.java:13947)
    at android.widget.AbsListView.draw(AbsListView.java:3693)
    at android.view.View.getDisplayList(View.java:12838)
    at android.view.View.getDisplayList(View.java:12880)
    at android.view.View.draw(View.java:13657)
    at android.view.ViewGroup.drawChild(ViewGroup.java:3083)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2920)
    at android.view.View.getDisplayList(View.java:12833)
    at android.view.View.getDisplayList(View.java:12880)
    at android.view.View.draw(View.java:13657)
    at android.view.ViewGroup.drawChild(ViewGroup.java:3083)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2920)
    at android.view.View.getDisplayList(View.java:12833)
    at android.view.View.getDisplayList(View.java:12880)
    at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3057)
    at android.view.View.getDisplayList(View.java:12775)
    at android.view.View.getDisplayList(View.java:12880)
    at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3057)
    at android.view.View.getDisplayList(View.java:12775)
    at android.view.View.getDisplayList(View.java:12880)
    at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3057)
    at android.view.View.getDisplayList(View.java:12775)
    at android.view.View.getDisplayList(View.java:12880)
    at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3057)
    at android.view.View.getDisplayList(View.java:12775)
    at android.view.View.getDisplayList(View.java:12880)
    at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3057)
    at android.view.View.getDisplayList(View.java:12775)
    at android.view.View.getDisplayList(View.java:12880)
    at android.view.HardwareRenderer$GlRenderer.buildDisplayList(HardwareRenderer.java:1411)
    at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:1359)
    at android.view.ViewRootImpl.draw(ViewRootImpl.java:2367)
    at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2239)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1872)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1004)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5481)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
    at android.view.Choreographer.doCallbacks(Choreographer.java:562)
    at android.view.Choreographer.doFrame(Choreographer.java:532)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
    at android.os.Handler.handleCallback(Handler.java:730)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:5103)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:

I've tried to save loaded bitmap reference in my service, but it didn't help.
Does anybody have idea what is wrong with my code?
Thanks in advance.

like image 200
Bersh Avatar asked Oct 13 '13 13:10

Bersh


2 Answers

I guess you're using an Android 4.3 device or newer. The RemoteControlClient implementation from 4.3 does a recycle on the artwork under certain conditions. See

http://androidxref.com/4.3_r2.1/xref/frameworks/base/media/java/android/media/RemoteControlClient.java#556

You essentially have to make a copy of the bitmap you if Build.VERSION.SDK_INT >= 18.

like image 169
David Burström Avatar answered Oct 22 '22 15:10

David Burström


In your onDestory() or onDestroyView() callbacks try calling Picasso.with(Context).cancelRequest(Target);

Credit to the guys here: https://github.com/square/picasso/issues/38

like image 34
AllDayAmazing Avatar answered Oct 22 '22 14:10

AllDayAmazing