Android - VideoView,在播放视频时获取当前位置?

Android - VideoView, getting current position as video is playing?

我有一个 VideoView 可以从内部存储器播放。当我的视频正在播放 VideoView 日志时 MediaPlayer: error (1, -1004)。我有一个 onErrorListener 附加到 VideoView,我想从那里管理这个错误。我的目标是获得最后一个位置(从 getCurrentPosition())并使用 seekTo(int position) 从该位置再次启动我的播放器。我的视频文件是有效的(通过在其他播放器上播放验证)。我现在的问题是从 VideoView 获取最后一个有效位置。当我执行 mp.getCurrentPosition / mVideoView.getCurrentPosition() 时,从 onError(MediaPlayer mp, int what, int extra) returns 0 调用 getCurrentPosition() (非常正确)。如何在播放时跟踪播放器的当前位置?

这是我的代码:

mVideoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer mp, int what, int extra) {
                switch (what) {
                    case MediaPlayer.MEDIA_ERROR_UNKNOWN:
                        Log.v("error", "media error unknown");
                        mediaErrorExtra(mp, extra, path);
                        break;
                    case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
                        Log.v("error", "media error server died");
                        mediaErrorExtra(mp, extra, path);
                        break;
                }
                return true;
            }
        });

private void mediaErrorExtra(MediaPlayer mp, int extra, String path){
        switch(extra){
            case MediaPlayer.MEDIA_ERROR_IO:

                if(!mp.isPlaying()){
                    Integer currentposition = mVideoView.getCurrentPosition();
                    if(currentposition != null){
                        Log.v("currentpos",Integer.toString(currentposition));
                    }
                    mVideoView.setVideoPath(path);
                    mVideoView.start();
                    //mVideoView.seekTo(currentposition);
                }
                break;
            case MediaPlayer.MEDIA_ERROR_MALFORMED:
                Log.v("error extra","media error malformed");
                break;
            case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:
                Log.v("error extra","media error unsupported");
                break;
            case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
                Log.v("error extra","media error timed out");
                break;
        }
    }

或者是否有任何侦听器在播放时提供播放器的当前位置?我可以使用 while(isPlaying()){int currentposition = mVideoView.getCurrrentPosition()} 但我认为这是一种糟糕的处理方式。任何建议将不胜感激。提前致谢。

你在 while 方面走在了正确的轨道上,但它需要更多的改进,因为 while 可能会完全阻止 UI。

所以你应该做的是使用一个Handler,它会每1秒触发一次检查MediaPlayer位置,我认为1秒是很合理的。

我已经使用这种方法为 MediaPlayer 实现了自定义 SeekBar,并且效果很好。

我展示了我使用的处理程序...

        private double currentTime = 0;
    private Handler mHandler = new Handler();

    //update Seekbar on UI thread
    public void updateProgressBar() {
        if (mHandler != null) {
            mHandler.postDelayedUpdateProgress 100);
        }
    }

 private Runnable UpdateProgress = new Runnable() {
      public void run() {
         currentTime = mediaPlayer.getCurrentPosition();
         txt.setText(String.format("%d min, %d sec",
         TimeUnit.MILLISECONDS.toMinutes((long) startTime),
         TimeUnit.MILLISECONDS.toSeconds((long) startTime) -
         TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.
         toMinutes((long) startTime)))
         );
         seekbar.setProgress((int)startTime);
         myHandler.postDelayed(this, 100);
      }
   };

你应该使用处理程序..

回答我的问题:

ScheduledExecutorService 帮助解决了这个问题:

以下是我在玩家玩游戏时获取当前位置的方法:

    ScheduledExecutorService mScheduledExecutorService;
    int mCurrentposition = 0;
    Runnable UpdateCurrentPosition = new Runnable(){

        @Override
        public void run() {
            mCurrentposition = mVideoView.getCurrentPosition();
        }
    };

    @Override
    protected void onCreate(){
        ...
        mScheduledExecutorService = new ScheduledExecutor(1);

        mScheduledExecutorService.scheduleWithFixedDelay(new Runnable(){
            @Override
            public void run() {
                mVideoView.post(UpdateCurrentPosition);
            }
        },3000,1000,TimeUnit.MILLISECONDS);
    }
private int time = 0;

private ScheduledExecutorService mScheduledExecutorService;
Runnable getPositionVideo = () -> {
    time = binding.videoView.getCurrentPosition();

};


   binding.videoView.setOnPreparedListener(mediaPlayer -> {
        binding.videoView.seekTo(position);
        binding.videoView.start();
        mScheduledExecutorService = new ScheduledThreadPoolExecutor(1);
        mScheduledExecutorService.scheduleWithFixedDelay(() -> {
            runOnUiThread(getPositionVideo);
            MediaControllerExitFullScreen.init(video_url, time);
        }, 1000, 1000, TimeUnit.MILLISECONDS);