Playing the next song using OnCompletionListener doesn't seem to work correctly consistently

Viewed 13

I'm working on a music player app, and I'm using OnCompletionListener to get the next song to play after the current one finishes. For some reason, my implementation doesn't seem to work correctly consistently. At times, when I drag the SeekBar to the end of the current song that's playing, there will be a few songs that are skipped, and sometimes, the app will just crash. Why is this happening, and how can I fix it?

Here is the code for my SeekBar and for making the SeekBar sync to the song that's playing:

seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                if(b) {
                    if(isPlaying) {
                        mediaPlayer.seekTo(i);
                    }
                }

                startTime.setText(formatSongDuration(i));
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                runOnUiThread(() -> {
                    if(mediaPlayer != null) {
                        seekBar.setProgress(mediaPlayer.getCurrentPosition());
                    }
                });
            }
        }, 0, 1000);

Here is the code for initializing the "full player" screen, which is a bottom sheet.

public static void initializeFullPlayer(Context context, int position, byte[] albumImage) {
        String artist;

        if(songs.get(position).getArtist().equals("<unknown>")) {
            artist = "Unknown Artist";
        } else {
            artist = songs.get(position).getArtist();
        }

        if(albumImage != null) {
            Glide.with(context).asBitmap()
                    .load(albumImage)
                    .into(miniAlbumImage);
        } else {
            Glide.with(context).asBitmap()
                    .load(R.drawable.song_icon)
                    .into(miniAlbumImage);
        }

        miniSongTitle.setText(songs.get(position).getTitle());
        miniArtistName.setText(artist);

        if(albumImage != null) {
            Glide.with(context).asBitmap()
                    .load(albumImage)
                    .into(fullAlbumImage);
        } else {
            Glide.with(context).asBitmap()
                    .load(R.drawable.song_icon)
                    .into(fullAlbumImage);
        }

        fullSongTitle.setText(songs.get(position).getTitle());
        fullArtistName.setText(artist);
        endTime.setText(formatSongDuration(songs.get(position).getDuration()));
    }

Here is the code for retrieving the song's album image and for playing the song:

public static byte[] getAlbumImage(String uri) {
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        retriever.setDataSource(uri);
        byte[] albumArt = retriever.getEmbeddedPicture();
        retriever.release();
        return albumArt;
    }

    public static void playSong(Context context, int position) {
        isPlaying = true;

        if(mediaPlayer != null) {
            mediaPlayer.release();
        }
        mediaPlayer = MediaPlayer.create(context, Uri.parse(songs.get(position).getPath()));
        mediaPlayer.start();

        int nextPosition = ++position;
        mediaPlayer.setOnCompletionListener(mediaPlayer -> {
            byte[] nextAlbumImage = getAlbumImage(songs.get(nextPosition).getPath());
            playSong(context, nextPosition);
            initializeFullPlayer(context, nextPosition, nextAlbumImage);
            seekBar.setMax(mediaPlayer.getDuration());
        });
    }

Any help would be highly appreciated!

0 Answers
Related