I'm using a SeekBar to display the progress of an audio file and for seeking to a certain time. For updating I use a Runnable which calls getCurrentPosition() on a MediaPlayer every second or so. Every time that happens there is a small amount of lag in the audio. Since I call it often, I get very noticeable stuttering while playing something. If it's relevant, I'm using setAudioStreamType(AudioManager.STREAM_MUSIC) and the file format is mp4 whith AAC audio (no video) and I'm using Android 2.3.4. Is there a way to get good audio with getCurrentPosition(), or do I have to implement my own progress calculations?
The Runnable:
private Runnable mUpdateTask = new Runnable(){
#Override
public void run() {
mSeekBar.setProgress((int) (mPlayer.getCurrentPosition() * 100 / mArrayAdapter.getRecording(mPlayingId).mDuration));
mHandler.postDelayed(mUpdateTask, 999);
}
};
I had the same problem or something similar.
When I've used mMediapPlayer.getCurrentPosition() in a TimerTask to update the SeekBar, I heard sound problems like echo but actually the problem wasn't there..
The issue is that I've also used SeekBar OnSeekBarChangeListener for manual seek but what happened is that update the seekBar from the TimerTask also triggered the listener, which did mp.seekTo(progress) and this, caused the mp to return back to that position again..
I've fixed it by using the fromUser argument as suggested here to do seek only if the seekBar changed manually.
Here is my sample code:
The TimerTask:
public void initializeTimerTask() {
mTimerTask = new TimerTask() {
public void run() {
int progress = mp.getCurrentPosition()/1000;
runOnUiThread(new Runnable() {
#Override
public void run() {
mSeekBar.setProgress(progress);
tvDuration.setText(DateUtils.formatElapsedTime(progress));
}
});
}
};
}
Listener:
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(mp != null && fromUser){
mp.seekTo(progress * 1000);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
you can do something like this:
private Runnable mUpdateTask = new Runnable(){
#Override
public void run()
{
mSeekBar.setProgress(mMediapPlayer.getCurrentPosition());
mHandler.postDelayed(mUpdateTask, 999);
}
};
you can also apply seek bar progress change listener as follow:
mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener()
{
#Override
public void onStopTrackingTouch(SeekBar seekBar)
{
}
#Override
public void onStartTrackingTouch(SeekBar seekBar)
{
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser)
{
if (fromUser)
{
int secProgress = seekBar.getSecondaryProgress();
if (secProgress> progress)
{
mMediapPlayer.seekTo(progress);
}
else
{
seekBar.setProgress(mSeekBar.getProgress());
}
}
}
});
mMediapPlayer.setOnBufferingUpdateListener(new OnBufferingUpdateListener()
{
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent)
{
mSeekBar.setSecondaryProgress((mSeekBar.getMax()/100)*percent);
}
});
I use this method to caluclate progress'
public static int getProgressPercentage(long currentDuration,
long totalDuration) {
Double percentage = (double) 0;
long currentSeconds = (int) (currentDuration / 1000);
long totalSeconds = (int) (totalDuration / 1000);
// calculating percentage
percentage = (((double) currentSeconds) / totalSeconds) * 100;
// return percentage
return percentage.intValue();
}
Note: mPlayer.getCurrentPosition() is not accurate. There are some bugs reported. I had problem that current position was higher than totalDuration.
Related
I want to make a seekbar that has multiple thumbs. I want the second / third thumbs to indicate certain section of the whole seekbar. For example :
---O--------V====V--------V======V-------
Here --- is seekbar, O is the first thumb, and V====V is a section, to show that a video file has some special scene in the section. I want the V to movable also.
Is there any way to make this function by only manipulating seekbar ?
Did you try something like this?
private void updateSeekBarStyle(SeekBar seekBar) {
int percentage = (int) ((seekBar.getProgress()/(float)seekBar.getMax())*100);
if(percentage > 75) {
seekBar.setThumb(ContextCompat.getDrawable(this, R.drawable.seekbar_thumb_red));
} else if (percentage > 50) {
seekBar.setThumb(ContextCompat.getDrawable(this, R.drawable.seekbar_thumb_blue));
} else if (percentage > 25) {
seekBar.setThumb(ContextCompat.getDrawable(this, R.drawable.seekbar_thumb_green));
}else{
seekBar.setThumb(ContextCompat.getDrawable(this, R.drawable.seekbar_thumb_default));
}
//seekBar.setProgressDrawable(ContextCompat.getDrawable(this, R.drawable.seekbar_progress));
}
You can call this method from onProgressChanged
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
updateSeekBarStyle(seekBar);
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) { }
#Override
public void onStopTrackingTouch(SeekBar seekBar) { }
});
I'm trying to animate the seekbar progress. It works fine when the progress update is not from user(which is what I want) but when the user drags the seekbar, I want the animation to stop. Right now what happens is when user drags the seekbar, the seekbar progress animates and there is delay because of the animation. I hope you guys get what I'm trying to say. I only want the animation when the input is not from user else animate.
Code:
circularSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
circularSeekBar.setEnabled(true);
if(fromUser) {
int seekprogress = (int) circularSeekBar.getProgress();
Intent io = new Intent(ConstantsForBroadCast.ACTION_PLAY_SEEKBAR);
io.putExtra("Progress", seekprogress);
getActivity().sendBroadcast(io);
}
}
public void Handler(final MediaPlayer mp){
currentSongLength= mp.getDuration();
final Handler mHandler = new Handler();
if((Activity)getActivity()!=null) {
((Activity) getActivity()).runOnUiThread(new Runnable() {
#Override
public void run() {
circularSeekBar.setMax((int) currentSongLength / 1000);
int mCurrentPosition = mp.getCurrentPosition() / 1000;
ObjectAnimator animation1 = ObjectAnimator.ofInt(circularSeekBar,"progress", mCurrentPosition);
animation1.setDuration(1000); // 0.5 second
animation1.setInterpolator(new DecelerateInterpolator());
animation1.start();
circularSeekBar.clearAnimation();
mHandler.postDelayed(this, 1000);
}
});
}
I've implemented a list of seekbars. According to my functionality, I want the sum of all seekbar not to exceed 100% for example if I drag first seekbar to 60% the next one will not exceed 40%.
I have made it work but whenever I drag the first one to some value (let's say 60 %) and then the second one to let's say 40% and then again when I try to drag the first one to decrease its value resets to 0. What is the problem with my code?
holder.shelfShareSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
remainingShelfShare = 100 - shelfShareSum;
holder.percentTextView.setText(String.valueOf(progress));
productShelfShareMap.get(((Products)list.get(position)).getProductID());
if(progress > remainingShelfShare){
holder.shelfShareSeekbar.setProgress(remainingShelfShare);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
list.get(position).setSetSlider(seekBar.getProgress());
shelfShareSum = 0;
productShelfShareMap.put(((Products)list.get(position)).getProductID(), Integer.parseInt(holder.percentTextView.getText().toString()));
for (HashMap.Entry<Integer, Integer> entry : productShelfShareMap.entrySet()){
shelfShareSum += entry.getValue();
}
}
});
Use SetMax function of seekbar to setvalue in SecondSeekbar.
int step = 1; // set it accordingly if you want data in 3.1,3.2 range
int max = 100;
int min; // if you want to set min criteria too.
shelfShareSeekbar.setOnSeekBarChangeListener(
new OnSeekBarChangeListener()
{
#Override
public void onStopTrackingTouch(SeekBar seekBar) {}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser)
{
// Ex :
// And finally set value of next seekbar based on firstone
secondseekbar.setMax((max - progress) / step);
}
}
);
I am making a audio player but i'm not able to update the Seek bar without any lag. Kindly try this code and help me!
private void updateProgress() { //To update progress of seekbar
long currentPosition = mpintro.getCurrentPosition();
txtstart.setText(String.format("%02d:%02d",
TimeUnit.MILLISECONDS.toMinutes(mpintro.getCurrentPosition()),
TimeUnit.MILLISECONDS.toSeconds(mpintro.getCurrentPosition()) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes((long)
mpintro.getCurrentPosition()))));
seekBar.setProgress((int) currentPosition); //To set seekbar to current position
}
public void playpause()
{
final int delay = 1000; //milliseconds
h.postDelayed(new Runnable(){
public void run() {
updateProgress();
h.postDelayed(this, 1000);
};
}, delay);
}
Change the onProgressChanged function as:
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean fromUser) {
if(fromUser) {
mplayer.seekTo(i);
}
}
This is because when your updateProgress funtion updates the seekbar, it also triggers the on onProgressChanged function, which again alters the seekbar and the audio lags.
So, add the if statement to check if the seekbar is changed only from user.
I have a seekbar which ranges from 0 - 100 .I want to create discrete points in the seekbar such that progress stops only at 0,10,20 and so on .I don't to stop in the midddle.
I tried with the below code and I am unable to succeed.
seekBar.setProgress(0);
//seekBar.incrementProgressBy(10);
seekBar.setMax(100);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { progress = progress / 10;
progress = progress * 10;
seekBarValue.setText(String.valueOf(progress));
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
int seekBarIntValue;
// seekBar.incrementProgressBy(10);
if((seekBar.getProgress()%10)!=0){
if((seekBar.getProgress()%10)> 5)
{
seekBarIntValue =(seekBar.getProgress()/10)+(seekBar.getProgress()%10);
}else{
seekBarIntValue =(seekBar.getProgress()/10)-(seekBar.getProgress()%10);
}
}else{
seekBarIntValue = (seekBar.getProgress());
}
seekBar.setProgress(seekBarIntValue);
}
});
Please help me out to solve this.
Try this.
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
// round progress up or down to the nearest 10
int roundedProgress = (int) (Math.rint((double) progress / 10) * 10);
if (fromUser)
{
seekBar.setProgress(roundedProgress);
}
}
for that you need to override onProgressChanged method.
i did it in this manner.
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int interval = 20;
progress = (progress/interval)*interval;
seekBar.setProgress(progress);
}
Try out below code
seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
int progress = 0;
#Override
public void onProgressChanged(SeekBar seekBar, int progresValue, boolean fromUser) {
progress = progresValue;
seekBarValue.setText(progress + "/" + seekBar.getMax());
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// Do something here, if you want to do anything at the start of
// touching the seekbar
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
// Display the value in textview
}
});
Example force SeekBar stop at 30
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(progress > 30){
seekBar.setProgress(30);
return;
}
tvProgress.setText(""+progress);
}
public void onStartTrackingTouch(SeekBar seekBar) {
}
public void onStopTrackingTouch(SeekBar seekBar) {
}
});