Когда seekBar обновляет видео MediaPlayer Android не гладко

Я воспроизводю видео через MediPlayer в своем приложении для Android, и у меня отображается SeekBar. Теперь я хочу, чтобы эта панель поиска автоматически обновлялась по мере воспроизведения видео, поэтому она должна автоматически перемещаться слева направо. На данный момент (код ниже) панель обновляется, и это делается с помощью работающего потока, который каждую секунду обновляет ход seekBar. Проблема в том, что это не гладко, и когда seekBar обновляется через seekProgress(), видео останавливается на долю секунды, и все очень нервно. Теперь я хотел бы, чтобы он обновлялся чаще, чем каждую секунду, а также сохранял функциональность, которую я уже реализовал, чтобы пользователь мог нажимать на панель и изменять ход видео.

Мне нужно что-то вроде приложения Android MediaPLayer, seekBar на прозрачном фоне, и все гладко, и я понятия не имею, как это делается.

Нет, в настоящее время, как вы видите из приведенного ниже кода, поток обновляется каждую секунду, поскольку он спит внутри метода f run. Я также пытался использовать обработчики для обновления потока пользовательского интерфейса, эффект был таким же. Я также расширил 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

    }
    }

person spirytus    schedule 19.08.2012    source источник


Ответы (1)


Ваша основная проблема заключается в вашем методе onProgressChanged().

Вы ищете указанную позицию каждый раз, когда изменяется прогресс seekBar, даже если это делается программно. Это означает, что каждый раз, когда вы вызываете seekBar.setProgress(mp.getCurrentPosition()), будет срабатывать onProgressChanged().

Поэтому мы меняем его на следующее:

public void onProgressChanged(SeekBar sb, int progress, boolean fromUser) {
    if (fromUser) {
        mp.seekTo(progress);
    }
}

Таким образом, он будет запущен только тогда, когда пользователь перемещает seekBar.

Более того, согласно этому ответу, было бы лучше заменить цикл while(true) на:

public void run() {
    seekBar.setProgress(mp.getCurrentPosition());
    if (mp.getCurrentPosition() < mp.getDuration()) {
        seekBar.postDelayed(this, MILLISECONDS);
    }

}
person Benito Bertoli    schedule 19.08.2012
comment
Большое спасибо за ваш ответ, я думаю, вы могли бы что-то понять, попробуем сегодня вечером и вернемся к вам. - person spirytus; 20.08.2012
comment
Также в отношении цикла while в методе run().. в вашей реализации нет цикла, поэтому он будет запускаться только один раз, верно? Вы предлагаете мне использовать его с обработчиком, чтобы последняя строка была handler.postDelayed(this,MILLISECONDS)? - person spirytus; 20.08.2012
comment
Нет, работает именно так, как я написал. В onPrepared() вместо запуска нового потока просто вызовите run(). - person Benito Bertoli; 20.08.2012
comment
ааа, кажется, я понял (Android docs в помощь), еще раз спасибо, обязательно попробую - person spirytus; 20.08.2012