我正在我的安卓应用程序中通过MediPlayer播放视频,并显示SeekBar。现在我希望这个搜索栏随着视频的进行自动更新,所以它应该自动从左到右移动。目前,(下面的代码)栏更新,这是通过运行线程完成的,每秒更新 seekBar 的进度。问题是它不流畅,当 seekBar 通过其 seekProgress() 更新时,视频会在一瞬间停止,一切都非常跳跃。现在我希望它每秒更新更频繁,并保留我已经实现的功能,以允许用户点击栏并更改视频的进度。
我追求的是像Android MediaPLayer应用程序那样的东西,seekBar在透明背景上,一切都很流畅,我不知道它是如何完成的。
不,目前,正如您从下面的代码中看到的那样,线程在 f run 方法中休眠时每秒更新一次。我还尝试使用处理程序来更新 UI 线程,效果是一样的。我还将 SeekBar 扩展到它自己的类,在那里有线程,这也不好,完全相同的效果。
如果有人能向我解释如何解决这个问题以及如何使用其他播放器应用程序完成,那就太好了。
public class FightPlayerActivity extends Activity implements Runnable, OnSeekBarChangeListener, SurfaceHolder.Callback, OnPreparedListener {
private MediaPlayer mp=null;
private SeekBar seekBar;
private Thread progressBarUpdater;
private String filePath;
private Handler handler=new Handler();
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Toast.makeText(this,"Create ", 2000).show();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
public void onStop()
{
super.onStop();
mp.stop();
mp.reset();
mp.release();
}
public void run()
{
while(true)
{
try {
progressBarUpdater.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
seekBar.setProgress(mp.getCurrentPosition());
// handler does have same effect, so video stops for split second
//handler.postDelayed(this, 1000);
}
}
public void onStart()
{
super.onStart();
setContentView(R.layout.fight_player);
filePath=getIntent().getStringExtra("filename");
filePath=Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)+"/FightAll_BJJ_Scoring/"+filePath;
Toast.makeText(this,filePath, 2000).show();
// seek bar
seekBar=(SeekBar) findViewById(R.id.seek_bar);
seekBar.setOnSeekBarChangeListener(this);
try {
SurfaceView sv=(SurfaceView) findViewById(id.video_preview);
SurfaceHolder sh=sv.getHolder();
sh.addCallback(this);
sh.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void stop(View view)
{
mp.seekTo(0);
mp.pause();
}
public void pause(View view)
{
mp.pause();
}
public void play(View view)
{
mp.start();
}
public void surfaceCreated(SurfaceHolder holder) {
try {
mp=new MediaPlayer();
mp.setDataSource(filePath);
mp.setDisplay(holder);
mp.setOnPreparedListener(this);
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.prepare();
//handler.removeCallbacks(this);
//handler.postDelayed(this, 1000);
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
public void onPrepared(MediaPlayer mediaplayer) {
mp.start();
seekBar.setMax(mp.getDuration());
progressBarUpdater=new Thread(this);
progressBarUpdater.start();
//handler.postDelayed(this, 1000);
}
public void onProgressChanged(SeekBar sb,int progress,boolean fromUser)
{
//Toast.makeText(this, progress, 2000).show();
mp.seekTo(progress);
}
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
onProgressChanged(seekBar,seekBar.getProgress(),true);
}
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
}
您的主要问题在于您的onProgressChanged()
方法。
每次 seekBar 进度更改时,您都会查找到指定位置,即使以编程方式完成也是如此。这意味着每次你打电话给seekBar.setProgress(mp.getCurrentPosition())
,onProgressChanged()
都会被解雇。
因此,我们将其更改为以下内容:
public void onProgressChanged(SeekBar sb, int progress, boolean fromUser) {
if (fromUser) {
mp.seekTo(progress);
}
}
这样,它只会在用户移动搜索栏时触发。
此外,根据这个答案,最好将你的while(true)循环替换为:
public void run() {
seekBar.setProgress(mp.getCurrentPosition());
if (mp.getCurrentPosition() < mp.getDuration()) {
seekBar.postDelayed(this, MILLISECONDS);
}
}