Android Mediaplayer到seekbar的进度更新不顺利?
我正在开发一款带有录音机和播放器的应用程序。我正在使用mediaplayer播放录制的.wav文件,同时我想更新到seekbar。一切正常,但我的问题是mediaplayer对seekbar的进度更新并没有顺利进行,若我们播放一个小文件,seekbar的拇指会在几秒钟或几秒钟之间跳跃 有谁能帮我找到一个解决办法,让我在seekbar顺利取得进展。我的代码如下所示。我被困在这里了Android Mediaplayer到seekbar的进度更新不顺利?,android,media-player,progress,seekbar,smooth,Android,Media Player,Progress,Seekbar,Smooth,我正在开发一款带有录音机和播放器的应用程序。我正在使用mediaplayer播放录制的.wav文件,同时我想更新到seekbar。一切正常,但我的问题是mediaplayer对seekbar的进度更新并没有顺利进行,若我们播放一个小文件,seekbar的拇指会在几秒钟或几秒钟之间跳跃 有谁能帮我找到一个解决办法,让我在seekbar顺利取得进展。我的代码如下所示。我被困在这里了 mediaPlayerIntiate(); mediaPlayerSetSource(); m
mediaPlayerIntiate();
mediaPlayerSetSource();
mMediaPlayer.start();
task = new TimerTask() {
@Override
public void run() {
Graphbar.post(new Runnable() {
@Override
public void run() {
if (mMediaPlayer != null) {
if (playButtonState == MediaMode.PLAY) {
if (mMediaPlayer.isPlaying()) {
Graphbar.setProgress(mMediaPlayer
.getCurrentPosition());
mediaPlayerUpdateTimer(mMediaPlayer
.getCurrentPosition());
enableRewindandForward();
}
}
}
}
});
}
};
timer = new Timer();
timer.schedule(task, 0, 8);
下面是我如何处理seekbar的
mediaPlayer.setOnPreparedListener(new OnPreparedListener(){
@Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer.start();
new SeekBarHandler().execute();
});
现在,我有一个名为SeekBarHandler的异步任务,它处理seekbar,如下所示:
public class SeekBarHandler extends AsyncTask<Void, Void, Void> {
@Override
protected void onPostExecute(Void result) {
Log.d("##########Seek Bar Handler ################","###################Destroyed##################");
super.onPostExecute(result);
}
@Override
protected void onProgressUpdate(Void... values) {
seekBar.setProgress(mediaPlayer.getCurrentPosition());
super.onProgressUpdate(values);
}
@Override
protected Void doInBackground(Void... arg0) {
while(mediaPlayer.isPlaying()&&isViewOn==true) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
onProgressUpdate();
}
return null;
}
}
在恢复时,我会像这样再次启动异步任务
protected void onResume() {
isViewOn=true;
new SeekBarHandler().execute();
super.onResume();
}
正如您所看到的,我使用一个布尔标志isViewOn来检查视图是否打开以处理seekbar mmediplayer.getCurrentPosition()以毫秒为单位返回当前时间,您正在将其更新为最大容量为100的Seekbar。制作一个公式,以文件长度和100表示。试试这个功能
MediaPlayer mMediaPlayer = new MediaPlayer();
final SeekBar mSeelBar = new SeekBar(this);
final int duration = mMediaPlayer.getDuration();
final int amoungToupdate = duration / 100;
Timer mTimer = new Timer();
mTimer.schedule(new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (!(amoungToupdate * mSeelBar.getProgress() >= duration)) {
int p = mSeelBar.getProgress();
p += 1;
mSeelBar.setProgress(p);
}
}
});
};
}, amoungToupdate);
当媒体播放器开始播放时,应该调用此过程。里面
mediaPlayer.setOnPreparedListener(new OnPreparedListener(){
@Override
public void onPrepared(MediaPlayer mp) {
**// call here**
}
});
更新
在几秒钟内更新125次不是你应该做的事情。请增加更新SeekBar的间隔时间。我在阅读了NullPointer的评论后添加了这一点,您遇到的问题与Android SeekBar的设计/实现方式有关。虽然它的功能非常好,但您受到所使用的段组合(即
seekbar.setMax(int)
)和处理程序延迟时间的限制
也就是说,我对SeekBar进行了子类化,以创建自己的SmoothSeekBar,它使用ViewPropertyAnimators而不是处理程序
请在此处查看:seekbar.setProgress()只接受int。因此,我们大多数人倾向于将已用百分比传递给此方法。但是,如果您需要更平滑的进程,那么您可以使用以毫秒为单位的持续时间作为最大值。然后我们可以每毫秒更新seekbar的进程。下面是一个例子,我每15毫秒更新一次,因为几乎每个android手机的刷新率都是每秒60帧
试试看{
mediaPlayer.start();
seekbar.setProgress(0);
seekbar.setMax(mediaPlayer.getDuration());
//更新进度条
参见khandler.postDelayed(updateSeekBar,15);
}捕获(IllegalArgumentException e){
e、 printStackTrace();
}捕获(非法状态){
e、 printStackTrace();
}
/**
*后台可运行线程
* */
private Runnable updateSeekBar=new Runnable(){
公开募捐{
long totalDuration=mediaPlayer.getDuration();
长currentDuration=mediaPlayer.getCurrentPosition();
//显示总持续时间
剩余的.setText(“+毫秒计时器(totalDuration currentDuration));
//显示播放完成的时间
已用.setText(“+millissecondstotimer(currentDuration));
//更新进度条
seekbar.setProgress((int)currentDuration);
//15毫秒=>~1000/60fps后再次调用此线程
参见Khandler.postDelayed(本,15);
}
};
/**
*函数将毫秒时间转换为
*定时器格式
*小时:分:秒
* */
公共字符串毫秒计时器(长毫秒){
字符串finalTimerString=“”;
字符串secondssString=“”;
//将总持续时间转换为时间
整数小时=(整数)(毫秒/(1000*60*60));
整数分钟=(整数)(毫秒%(1000*60*60))/(1000*60);
整数秒=(整数)((毫秒%(1000*60*60))%(1000*60)/1000);
//如果有,请加上小时数
如果(小时数>0){
finalTimerString=hours+“:”;
}
//如果是一位数字,则在0到秒之前加上前缀
如果(秒<10){
secondsString=“0”+秒;
}否则{
secondsString=“”+秒;
}
finalTimerString=finalTimerString+minutes+“:”+secondsString;
//返回计时器字符串
返回finalTimerString;
}
如果记录的总持续时间小于某个值,您是否尝试过只设置搜索栏的动画(使用属性动画),而不是调用mmediplayer.getCurrentPosition()?建议:不要在一秒钟内调用new Runnable()125次。你制造的垃圾太多了。你在什么设备上测试这个?我尝试了你的代码,seekbar更新很顺利,即使是在1
秒播放时间(在nexus 4上)。我在播放.wav文件时遇到问题。你能告诉我1秒wav文件在ma代码中是如何工作的吗?谢谢,是的,这工作正常(不像我预期的那样)当mediaplayer播放时,正在更新进度条……但seekbar的抖动仍然存在:-(…我需要尽可能平滑地更新它…谢谢你帮我尝试了更多的方法…非常感谢…但遗憾的是它仍然没有那么平滑…嗨,Sreedev,这里是另一种方法,你可以尝试移动seekbar。我在回来时写了这个答案,所以我不知道它是否仍然有效,但值得一试:如果你需要保持线程运行一段时间在一段时间内,强烈建议您使用java.util.concurrent包提供的各种API,如Executor、ThreadPoolExecutor和FutureTask。
另外,默认情况下,AsyncTask在SERIAL_Executor上运行,您可能希望在THREAD_POOL_Executor上执行它,以确保其他任务不会被阻止。实际上我有totaldurat吗以毫秒为单位播放音频文件,am在播放前将Graphbar.setMax(“totalduration”)设置为seekbar…seekbar max以毫秒为单位,progres upadate也以毫秒为单位,因此这不是问题所在…抱歉,ma问题中缺少部分代码…-)好的,那么你可以尝试Runnable来更新进度,不推荐使用计时器。它消耗内存泄漏。我使用Runnable来更新seekbar,但它一点也不平滑。更新时会发出咯咯的笑声。所以我现在做的是更新seekba
mediaPlayer.setOnPreparedListener(new OnPreparedListener(){
@Override
public void onPrepared(MediaPlayer mp) {
**// call here**
}
});
try{
mediaPlayer.start();
seekbar.setProgress(0);
seekbar.setMax(mediaPlayer.getDuration());
// Updating progress bar
seekHandler.postDelayed(updateSeekBar, 15);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
/**
* Background Runnable thread
* */
private Runnable updateSeekBar = new Runnable() {
public void run() {
long totalDuration = mediaPlayer.getDuration();
long currentDuration = mediaPlayer.getCurrentPosition();
// Displaying Total Duration time
remaining.setText(""+ milliSecondsToTimer(totalDuration-currentDuration));
// Displaying time completed playing
elapsed.setText(""+ milliSecondsToTimer(currentDuration));
// Updating progress bar
seekbar.setProgress((int)currentDuration);
// Call this thread again after 15 milliseconds => ~ 1000/60fps
seekHandler.postDelayed(this, 15);
}
};
/**
* Function to convert milliseconds time to
* Timer Format
* Hours:Minutes:Seconds
* */
public 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;
}
player.prepare(); // or start()
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
service.scheduleWithFixedDelay(new Runnable()
{
@Override
public void run()
{
progressBar.setProgress(player.getCurrentPosition());
}
}, 1, 1, TimeUnit.MICROSECONDS);
private void startPlaying() {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(audioPlayerName);
mediaPlayer.prepare();
mediaPlayer.start();
setAudioProgress(); //call method
} catch (Exception e) {
e.printStackTrace();
}
}
public void setAudioProgress() {
total_duration = mediaPlayer.getDuration();
binding.total.setText(timeConversion((long) total_duration));
binding.current.setText(timeConversion((long) current_pos));
binding.seekbar.setMax((int) total_duration);
runnable = new Runnable() {
@Override
public void run() {
try {
current_pos = mediaPlayer.getCurrentPosition();
binding.current.setText(timeConversion((long) current_pos));
binding.seekbar.setProgress((int) current_pos);
handlerProgressBar.postDelayed(this, 1000);
Log.e(LOG_TAG, "11111");
} catch (IllegalStateException ed) {
ed.printStackTrace();
}
}
};
handlerProgressBar.postDelayed(runnable, 1000);
}