Reputation: 4343
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
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
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
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