Daniele
Daniele

Reputation: 4343

Android - SeekBar and MediaPlayer

I needed to connect my SeekBar with my MediaPlayer in my App.

I set up the SeekBar via xml like this:

<SeekBar
        android:id="@+id/song_seekbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"/>

and followed this SO answer to implement it.

This is my code:

public class Song_main extends AppCompatActivity {
private final int SONG_REQUEST_CODE = 1;

private Uri song;
private TextView selectSong;
private SeekBar seekBar;
private Handler handler;
private MediaPlayer mediaPlayer;


private boolean repeatPressedTwice = false;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.app_bar_song_main);

    Toolbar toolbar = (Toolbar) findViewById(R.id.song_main_toolbar);
    setSupportActionBar(toolbar);
    getSupportActionBar().setDisplayShowTitleEnabled(false);

    seekBar = (SeekBar) findViewById(R.id.song_seekbar);
    handler = new Handler();

    notSelected();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.song, menu);

    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();

    if (id == R.id.song_plus) {
        Intent selectIntent = new Intent(Intent.ACTION_GET_CONTENT);
        selectIntent.setType("audio/*");
        startActivityForResult(selectIntent, SONG_REQUEST_CODE);
    }

    return true;
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == SONG_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
        if ((data != null) && (data.getData()!=null)) {
            song = data.getData();
            setup();
        }
    }
}

private void notSelected() {
    selectSong = (TextView) findViewById(R.id.select_song_textview);
    selectSong.setText(getResources().getString(R.string.song_not_selected));
}

public void onPlayButtonClicked(View v) {
    ImageButton pb = (ImageButton) findViewById(R.id.song_play_button);
    if (!mediaPlayer.isPlaying()) {
        mediaPlayer.start();
        pb.setImageResource(R.drawable.pause);

        updateSeekBar();

    } else {
        mediaPlayer.pause();
        pb.setImageResource(R.drawable.ic_play_arrow_white_24dp);
    }
}

public void onControlsClicked(View v) {
    if (v.getId() == R.id.fast_forward) {
        int pos = mediaPlayer.getCurrentPosition();
        pos += 1500;
        mediaPlayer.seekTo(pos);
    }
    else if (v.getId() == R.id.fast_backward) {
        int pos = mediaPlayer.getCurrentPosition();
        pos -= 1500;
        mediaPlayer.seekTo(pos);
    }
    else if (v.getId() == R.id.skip_backward) {
        mediaPlayer.seekTo(0);
    }
}

public void onRepeatClicked(View v) {
    if (!repeatPressedTwice) {
        // TODO: change visual color of repeat button
        mediaPlayer.setLooping(true);
        Toast.makeText(this, "repeat enabled", Toast.LENGTH_SHORT).show();
        repeatPressedTwice = true;
    } else {
        mediaPlayer.setLooping(false);
    }

}

private void setup() {
    /* the song has been select setup the interface */


    /* displays song name in title */
    TextView titleView = (TextView) findViewById(R.id.song_appbar_title);
    String songName;

    ContentResolver contentResolver = this.getContentResolver();
    Cursor cursor = contentResolver.query(song, null, null, null, null);

    if (cursor != null && cursor.moveToFirst()) {
        songName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
        titleView.setText(songName);
    }


    /* removes the notSelected String */
    selectSong.setVisibility(View.GONE);

    /* setup media player */
    mediaPlayer = new MediaPlayer();
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    try {
        mediaPlayer.setDataSource(getApplicationContext(), song);
        mediaPlayer.prepareAsync();
    } catch (IOException e) {
        Toast.makeText(this, "file not found", Toast.LENGTH_SHORT).show();
    }

    mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mp) {
            /* show media player layout */
            RelativeLayout mpl = (RelativeLayout) findViewById(R.id.media_player_layout);
            mpl.setVisibility(View.VISIBLE);

            mediaPlayer.start();
            ImageButton pb = (ImageButton) findViewById(R.id.song_play_button);
            pb.setImageResource(R.drawable.pause);

        }
    });

    mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mp) {
            ImageButton pb = (ImageButton) findViewById(R.id.song_play_button);
            pb.setImageResource(R.drawable.ic_play_arrow_white_24dp);
        }
    });



    seekBar = (SeekBar) findViewById(R.id.song_seekbar);
    seekBar.setMax(mediaPlayer.getDuration()); 

    updateSeekBar();


}

private void updateSeekBar() {
    seekBar.setProgress(mediaPlayer.getCurrentPosition()/1000);
    handler.postDelayed(runnable, 1000);
}

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        updateSeekBar();
    }
};


@Override
public void onStop() {
    super.onStop();
    if (mediaPlayer!=null)
        mediaPlayer.stop();
}
}

The process starts from the onOptionsItemSelected method.

The seekBar behaves correctly, it increments every second. The problem now is that it finishes way before the song finishes.

I tried adding

seekBar.setMax(mediaPlayer.getDuration());

in the setup method, but that causes the bar not to move at all.

Upvotes: 5

Views: 9250

Answers (3)

Neha kumari
Neha kumari

Reputation: 31

You have implement OnSeekBarChangeListener and in onCreate() add the below line:-

seekBar = (SeekBar) findViewById(R.id.seekBar);

And override the onProgressChanged() method , in this method you can set the progress in the seekbar using the below line:

mPlayer.seekTo(progress); 
seekBar.setProgress(progress);

or

After you initialise your MediaPlayer and for example press the play button, you should create an handler and post runnable so you can update your SeekBar (in the UI thread itself) with the current position of your MediaPlayer like this :

private Handler mHandler = new Handler();
//Make sure you update Seekbar on UI thread
MainActivity.this.runOnUiThread(new Runnable(){
    @Override
    public void run() {
        if(mMediaPlayer != null){
            int mCurrentPosition = mMediaPlayer.getCurrentPosition() / 1000;
            mSeekBar.setProgress(mCurrentPosition);
        }
    mHandler.postDelayed(this, 1000);
    }
});

and update that value every second.

If you need to update the MediaPlayer's position while user drag your SeekBar you should add OnSeekBarChangeListener to your SeekBar and do it there :

mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
     @Override
     public void onStopTrackingTouch(SeekBar seekBar) {

     }
     @Override
     public void onStartTrackingTouch(SeekBar seekBar) {

     }
     @Override
     public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
         if(mMediaPlayer != null && fromUser){
             mMediaPlayer.seekTo(progress * 1000);
     }
  }
});

Upvotes: 3

Waqas Ahmed Ansari
Waqas Ahmed Ansari

Reputation: 1699

You need to define separate Runnable and trigger it every x miliseconds (depends on you) once MediaPlayer starts.

Define a function updateSeekbar like,

private void updateSeekBar() {
    audioSeek.setProgress(player.getCurrentPosition());
    txtCurrentTime.setText(milliSecondsToTimer(player.getCurrentPosition()));
    seekHandler.postDelayed(runnable, 50);
}

And Runnable

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        updateSeekBar();
    }
};

Now you just have to call updateSeekbar once when playing starts. In your case:

public void onPlayButtonClicked(View v) {
    ImageButton pb = (ImageButton) findViewById(R.id.song_play_button);
    if (!mediaPlayer.isPlaying()) {
        mediaPlayer.start();
        pb.setImageResource(R.drawable.pause);

        updateSeekBar();

    } else {
        mediaPlayer.pause();
        pb.setImageResource(R.drawable.ic_play_arrow_white_24dp);
    }
}

FYI

Function milliSecondsToTimer works as follows

private String milliSecondsToTimer(long milliseconds) {
    String finalTimerString = "";
    String secondsString = "";

    // Convert total duration into time
    int hours = (int) (milliseconds / (1000 * 60 * 60));
    int minutes = (int) (milliseconds % (1000 * 60 * 60)) / (1000 * 60);
    int seconds = (int) ((milliseconds % (1000 * 60 * 60)) % (1000 * 60) / 1000);
    // Add hours if there
    if (hours > 0) {
        finalTimerString = hours + ":";
    }

    // Prepending 0 to seconds if it is one digit
    if (seconds < 10) {
        secondsString = "0" + seconds;
    } else {
        secondsString = "" + seconds;
    }

    finalTimerString = finalTimerString + minutes + ":" + secondsString;

    // return timer string
    return finalTimerString;
}

UPDATE

You have called setMax at the wrong place. Update setup() function as follows

private void setup() {
    /* the song has been select setup the interface */
    /* displays song name in title */
    TextView titleView = (TextView) findViewById(R.id.song_appbar_title);
    String songName;

    ContentResolver contentResolver = this.getContentResolver();
    Cursor cursor = contentResolver.query(song, null, null, null, null);

    if (cursor != null && cursor.moveToFirst()) {
        songName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
        titleView.setText(songName);
    }


    /* removes the notSelected String */
    selectSong.setVisibility(View.GONE);

    /* setup media player */
    mediaPlayer = new MediaPlayer();
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    try {
        mediaPlayer.setDataSource(getApplicationContext(), song);
        mediaPlayer.prepareAsync();
    } catch (IOException e) {
        Toast.makeText(this, "file not found", Toast.LENGTH_SHORT).show();
    }

    mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mp) {
        /* show media player layout */
            seekBar.setMax(mediaPlayer.getDuration());

            RelativeLayout mpl = (RelativeLayout) findViewById(R.id.media_player_layout);
            mpl.setVisibility(View.VISIBLE);
            mediaPlayer.start();

            updateSeekBar();


            ImageButton pb = (ImageButton) findViewById(R.id.song_play_button);
            pb.setImageResource(R.drawable.pause);

        }
    });

    mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mp) {
            ImageButton pb = (ImageButton) findViewById(R.id.song_play_button);
            pb.setImageResource(R.drawable.ic_play_arrow_white_24dp);
        }
    });

}

Upvotes: 5

Lavanya Velusamy
Lavanya Velusamy

Reputation: 333

you need to update your Seek bar when you play a song

public void updateProgressBar() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mHandler.postDelayed(mUpdateTimeTask, 100);
            }
        });

    }  

Below Runnable method to update seekbar

private Runnable mUpdateTimeTask = new Runnable() {
        public void run() {
            if (MusicService.isRunning()) {
                duration = MusicService.getDur();
                long currSongPosition = MusicService.getPosn();
                totTime.setText(Utility.milliSecondsToTimer(duration));
                fromTime.setText(Utility.milliSecondsToTimer(currSongPosition));
                int progress = Utility.getProgressPercentage(currSongPosition, duration);
            songProgressBar.setProgress(progress);
            updateProgressBar();
        }
    }
};

Using this below function you can get progress percentage from song current position and song duration

 public static int getProgressPercentage(long currentDuration, long totalDuration) {
        Double percentage;
        long currentSeconds = (int) (currentDuration / 1000);
        long totalSeconds = (int) (totalDuration / 1000);
        percentage = (((double) currentSeconds) / totalSeconds) * 100;
        return percentage.intValue();
    }

Upvotes: 2

Related Questions