Tuesday 10 November 2020

imageView.setImageBitmap(bitmap); does not work with a valid, correctly scaled Bitmap

I am trying to display a Bitmap in an ImageView like I did in two other places in my project.

To start, I know I have a valid Bitmap because the debugger shows it and it gets displayed in two other ImageViews. Nonetheless, here is my code to get the Bitmap.

    public static Bitmap getThumbnail(AudioUri audioURI, Context context){
        Bitmap bitmap = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            try {
                bitmap = context.getContentResolver().loadThumbnail(
                        audioURI.getUri(), new Size(128, 128), null);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            MediaMetadataRetriever mmr = new MediaMetadataRetriever();
            try {
                mmr.setDataSource(context.getContentResolver().openFileDescriptor(
                        audioURI.getUri(), "r").getFileDescriptor());
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            InputStream inputStream = null;
            if (mmr.getEmbeddedPicture() != null) {
                inputStream = new ByteArrayInputStream(mmr.getEmbeddedPicture());
            }
            mmr.release();
            bitmap = BitmapFactory.decodeStream(inputStream);
        }
        return bitmap;
    }

I am not sure the else part works because I have not yet tested it.

Here is my successful attempt at loading a Bitmap into an ImageView the first time.

The xml

    <ImageView
        android:id="@+id/image_view_song_art"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        android:layout_weight="14"
        app:srcCompat="@drawable/music_note_black_48dp"
        android:background="@color/colorPrimary"/>

Here is where I load the BitMap

    private void updateSongArt() {
        ImageView imageViewSongArt = findViewById(R.id.image_view_song_art);
        if (imageViewSongArt != null && serviceMain != null) {
            Bitmap bitmap =
                    AudioUri.getThumbnail(serviceMain.getCurrentSong(), getApplicationContext());
            if (bitmap == null) {
                imageViewSongArt.setImageDrawable(ResourcesCompat.getDrawable(
                        getResources(), R.drawable.music_note_black_48dp, null));
                imageViewSongArt.setBackgroundColor(
                        getResources().getColor(R.color.colorPrimary));
            } else {
                imageViewSongArt.setImageBitmap(bitmap);
                imageViewSongArt.setBackgroundColor(
                        getResources().getColor(R.color.colorOnPrimary));
            }
        }
    }

I am assuming I got lucky here because I did not do any dynamic resizing. This leads me to believe my dynamic resizing is wrong. I added dynamic resizing to the code above and the Bitmap is correctly displayed.

    private void updateSongArt() {
        ImageView imageViewSongArt = findViewById(R.id.image_view_song_art);
        if (imageViewSongArt != null && serviceMain != null) {
            Bitmap bitmap =
                    AudioUri.getThumbnail(serviceMain.getCurrentSong(), getApplicationContext());
            if (bitmap == null) {
                imageViewSongArt.setImageDrawable(ResourcesCompat.getDrawable(
                        getResources(), R.drawable.music_note_black_48dp, null));
                imageViewSongArt.setBackgroundColor(
                        getResources().getColor(R.color.colorPrimary));
            } else {
                    int songArtHeight = imageViewSongArt.getMeasuredHeight();
                    if (songArtHeight < 1) {
                        songArtHeight = bitmap.getHeight();
                    }
                int songArtWidth = imageViewSongArt.getMeasuredWidth();
                if (songArtWidth < 1) {
                    songArtWidth = bitmap.getWidth();
                }
                if(songArtWidth > songArtHeight){
                    songArtWidth = songArtHeight;
                } else{
                    songArtHeight = songArtWidth;
                }
                Bitmap bitmap2 = FragmentPaneSong.getResizedBitmap(bitmap, songArtWidth, songArtHeight);
                if(bitmap2 != null) {
                    imageViewSongArt.setImageBitmap(bitmap2);
                } else {
                    imageViewSongArt.setImageBitmap(bitmap);
                }
                imageViewSongArt.setBackgroundColor(
                        getResources().getColor(R.color.colorOnPrimary));
            }
        }
    }

Here is the failing code

The xml

    <ImageView
        android:id="@+id/imageViewSongPaneSongArt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="4dp"
        android:background="@color/colorPrimary"
        android:src="@drawable/music_note_black_48dp" />

Here I get the width and height and resize and set the Bitmap to the ImageView.

 private void updateSongPaneArt() {
        int songArtHeight = getSongArtHeight();
        int songArtWidth = getSongArtWidth();
        setImageViewSongPaneArt(songArtWidth, songArtHeight);
    }

    private int getSongArtHeight() {
        ImageView imageViewSongPaneSongArt = findViewById(R.id.imageViewSongPaneSongArt);
        if (imageViewSongPaneSongArt != null && serviceMain != null) {
            int songArtHeight = imageViewSongPaneSongArt.getMeasuredHeight();
            if (songArtHeight > 0) {
                serviceMain.setSongPaneArtHeight(songArtHeight);
            } else {
                songArtHeight = serviceMain.getSongPaneArtHeight();
            }
            return songArtHeight;
        }
        return -1;
    }

    private int getSongArtWidth() {
        ImageView imageViewSongPaneSongArt = findViewById(R.id.imageViewSongPaneSongArt);
        if (imageViewSongPaneSongArt != null && serviceMain != null) {
            int songArtWidth = imageViewSongPaneSongArt.getMeasuredWidth();
            if (songArtWidth > 0) {
                serviceMain.setSongPaneArtWidth(songArtWidth);
            } else {
                songArtWidth = serviceMain.getSongPaneArtWidth();
            }
            return songArtWidth;
        }
        return -1;
    }

    private void setImageViewSongPaneArt(int songArtWidth, int songArtHeight) {
        ImageView imageViewSongPaneSongArt = findViewById(R.id.imageViewSongPaneSongArt);
        if (imageViewSongPaneSongArt != null && serviceMain != null) {
            Bitmap bitmapSongArt = AudioUri.getThumbnail(
                    serviceMain.getCurrentSong(), getApplicationContext());
            if (bitmapSongArt != null) {
                Bitmap bitmapSongArtResized = FragmentPaneSong.getResizedBitmap(
                        bitmapSongArt, songArtWidth, songArtHeight);
                imageViewSongPaneSongArt.setImageDrawable(null);
                imageViewSongPaneSongArt.setImageBitmap(bitmapSongArtResized);
                imageViewSongPaneSongArt.invalidate();
            } else {
                Bitmap defaultBitmap = getDefaultBitmap(songArtWidth, songArtHeight);
                if (defaultBitmap != null) {
                    imageViewSongPaneSongArt.setImageBitmap(defaultBitmap);
                }
            }
        }
    }

    public static Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) {
        int width = bm.getWidth();
        int height = bm.getHeight();
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);
        return Bitmap.createBitmap(
                bm, 0, 0, width, height, matrix, false);
    }

I have tried removing the margins from the dimensions and that does not work. The Bitmap that is generated by the getResizedBitmap() method has the correct size; the debugger verifies it. It matches the width int songArtWidth = imageViewSongPaneSongArt.getMeasuredWidth(); which I verified gets returned as the width. I am not sure what is going on.

I can set the Bitmap without resizing and it expands to the large size, but it uses the drawable as the image still. Even after imageViewSongPaneSongArt.setImageDrawable(null);. These are the only spots in my code where the ImageView is mutated and the debugger shows that imageViewSongPaneSongArt.setImageBitmap(defaultBitmap); IS NOT called.

I have also tried to invalidate the ImageView with no success.

What is going on?



from imageView.setImageBitmap(bitmap); does not work with a valid, correctly scaled Bitmap

No comments:

Post a Comment