Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/233.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android ExoPlayer已更改_Android_Listener_Progress_Exoplayer - Fatal编程技术网

Android ExoPlayer已更改

Android ExoPlayer已更改,android,listener,progress,exoplayer,Android,Listener,Progress,Exoplayer,如何在ExoPlayer上监视进度变化? 我试图实现一个隐藏的MediaController和重写setonseekbarchaneglistener方法,但目前没有成功。我想知道是否有另一种方法可以收听ExoPlayer进程。不确定这是最好的方法,但我是通过重载轨迹渲染器来实现的 我使用的是videoPlayer.getBufferedPercentage(),但您也可以自己计算百分比,只需使用TrackRenderer的getBufferedPositionUs()和getDurationU

如何在
ExoPlayer
上监视进度变化?

我试图实现一个隐藏的
MediaController
和重写
setonseekbarchaneglistener
方法,但目前没有成功。我想知道是否有另一种方法可以收听
ExoPlayer
进程。

不确定这是最好的方法,但我是通过重载
轨迹渲染器来实现的

我使用的是
videoPlayer.getBufferedPercentage()
,但您也可以自己计算百分比,只需使用
TrackRenderer
getBufferedPositionUs()
getDurationUs()

公共接口监听器{
公共进度变更(长期进度);
}
公共类CustomVideoRenderer扩展了MediaCodeVideoTrackRenderer{
长期进展=0;
private final CopyOnWriteArraySet progressListeners=new CopyOnWriteArraySet();
// [...]
//跳过的构造函数
// [...]
public void doSomeWork(long positionUs,long elapsederrealtimeus)抛出ExoPlaybackException{
super.doSomeWork(位置、延时);
long tmpProgress=videoPlayer.getBufferedPercentage();
if(tmpProgress!=此.progress){
this.progress=tmpProgress;
for(ProgressListener ProgressListener:this.progressListeners){
progressListener.onProgressChange(进度);
}
}
}
public void addProgressListener(ProgressListener侦听器){
this.progressListeners.add(listener);
}
}

我知道这个问题很老了。但是,我是在实现
ExoPlayer
时发现这一点的。这是为了帮助以后也这样做的其他人:)

因此,我遵循以下方法来跟踪播放的进度。这是在
ExoPlayer
googledocs中完成的方式。它可以根据需要工作

在中签出PlayerControlView.java

updateProgressBar()
是更新
SeekBar
进度的函数:

private void updateProgressBar() {
    long duration = player == null ? 0 : player.getDuration();
    long position = player == null ? 0 : player.getCurrentPosition();
    if (!dragging) {
        mSeekBar.setProgress(progressBarValue(position));
    }
    long bufferedPosition = player == null ? 0 : player.getBufferedPosition();
    mSeekBar.setSecondaryProgress(progressBarValue(bufferedPosition));
    // Remove scheduled updates.
    handler.removeCallbacks(updateProgressAction);
    // Schedule an update if necessary.
    int playbackState = player == null ? Player.STATE_IDLE : player.getPlaybackState();
    if (playbackState != Player.STATE_IDLE && playbackState != Player.STATE_ENDED) {
        long delayMs;
        if (player.getPlayWhenReady() && playbackState == Player.STATE_READY) {
            delayMs = 1000 - (position % 1000);
            if (delayMs < 200) {
                delayMs += 1000;
            }
        } else {
            delayMs = 1000;
        }
        handler.postDelayed(updateProgressAction, delayMs);
    }
}

private final Runnable updateProgressAction = new Runnable() {
    @Override
    public void run() {
        updateProgressBar();
    }
};

希望这有帮助

这至少适用于Exoplayer 2

有四种播放状态:状态空闲、状态缓冲、状态就绪和状态结束

检查播放状态很容易。至少有两种解决方案:if语句或switch语句

无论播放状态如何,您都可以执行您的方法或设置其他内容,例如progressbar

@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
    if (playbackState == ExoPlayer.STATE_ENDED) {
        showControls();
        Toast.makeText(getApplicationContext(), "Playback ended", Toast.LENGTH_LONG).show();
    }
    else if (playbackState == ExoPlayer.STATE_BUFFERING)
    {
        progressBar.setVisibility(View.VISIBLE);
        Toast.makeText(getApplicationContext(), "Buffering..", Toast.LENGTH_SHORT).show();
    }
    else if (playbackState == ExoPlayer.STATE_READY)
    {
        progressBar.setVisibility(View.INVISIBLE);
    }

}

扩展您当前的播放器类(例如SimpleExoPlayer)并添加


然后在播放器活动中,只需实现接口并使用
player.startProgressUpdater()启动更新

为了清楚起见,进度事件没有内置的EventListener,但是您可以在updateProgress()函数中调用Handler.postDelayed来获取当前进度

 private void updateProgress(){

    //get current progress 
    long position = player == null ? 0 : player.getCurrentPosition();
    //updateProgress() will be called repeatedly, you can check 
    //player state to end it
    handler.postDelayed(updateProgressAction,1000)

}

 private final Runnable updateProgressAction = new Runnable() {
    @Override
    public void run() {        
      updateProgress();
    }
};

有关更多详细信息,请参阅inside Exoplayer的源代码

试试这个,它对我有用:

handler = new Handler();
runnable = new Runnable() {
      @Override
      public void run() {
           progressbar.setProgress((int) ((exoPlayer.getCurrentPosition()*100)/exoPlayer.getDuration()));
           handler.postDelayed(runnable, 1000);
      }
};
handler.postDelayed(runnable, 0);
这里,

  • getCurrentPosition()
    :以毫秒为单位返回当前播放位置
  • getDuration()
    :曲目的持续时间(毫秒)

仅将onTouchListener与MotionEvent.ACTION\u一起使用

    SeekBar exo_progress = (SeekBar) findViewById(R.id.exo_progress);
    exo_progress.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (event.getAction() == MotionEvent.ACTION_UP) {
                        //put your code here!!
                    }
                    return false;
                }
            });

我发现了一个使用RxJava的非常优雅的解决方案。这也涉及到轮询模式,但我们确保每1秒使用一次间隔进行轮询

public Observable<Long> playbackProgressObservable = 
                            Observable.interval(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
要最终连接到一起,只需调用subscribe,进度更新将每秒发出一次:

playbackProgressObservable.subscribe( { progress -> // Update logic here } )
注意:
可观察。间隔
调度程序的默认调度程序
上运行。计算()
。因此,您可能需要添加一个
observeOn()
操作符,以确保将结果发送到正确的线程

playbackProgressObservable
    .observeOn(AndroidSchedulers.mainThread())        
    .subscribe(progress -> {}) // Update logic here 
上述声明将为您提供一个一次性,在您完成观察后必须将其处理掉。 您可以这样做->

private var playbackDisposable: Disposable? = null

       playbackDisposable = playbackProgressObservable
        .observeOn(AndroidSchedulers.mainThead())        
        .subscribe(progress -> {}) // Update logic here
然后处理资源->

playbackDisposable?.dispose()

我不确定这是否是正确的方法,但我使用和
TimerTask
来更新正在播放的音频的进度。 在我的MusicController课程中,我提出:

private void sendElapsedDuration() {
    //To send the current elapsed time
    final Timer t = new Timer();
    Runnable r = new Runnable() {
        @Override
        public void run() {
            t.schedule(new TimerTask() {
                @Override
                public void run() {
                    EventBus.getDefault().post(
                            new ProgressNotification(
                                    player.getCurrentPosition(), player.getDuration())
                    );
                    if (player.getCurrentPosition() >= player.getDuration() ){
                        // The audio is ended, we pause the playback,
                        // and reset the position
                        player.seekTo(0);
                        player.setPlayWhenReady(false);
                        this.cancel();
                        // stopping the Runnable to avoid memory leak
                        mainHandler.removeCallbacks(this);
                    }
                }
            },0,1000);
        }
    };
    if(player != null) {
        if (player.getPlaybackState() != Player.STATE_ENDED)
            mainHandler.postDelayed(r, 500);
        else {
            //We put the TimerTask to sleep when audio is not playing
            t.cancel();
        }
    }

}
然后,在将侦听器添加到SimpleExoPlayer实例时,我调用了
onPlayerStateChanged
中的方法。上面的代码通过EventBus发送每1秒(1000毫秒)播放的音频的经过时间和总持续时间。然后在承载SeekBar的活动中:

@Subscribe(threadMode = ThreadMode.MAIN)
    public void updateProgress(ProgressNotification pn) {
        seekBar.setMax((int) pn.duration);
        seekBar.setProgress((int) pn.currentPosition);
    }

如果您想完成此操作,只需听
onpositionintercontinuction()
。如果正在清除
seekbar
,它将为您提供信息如果您完全或部分使用播放器视图或播放器控件视图(仅用于按钮或其他),您可以直接从中设置进度侦听器:

 PlayerControlView playerControlView = miniPlayerCardView.findViewById(R.id.playerView);
    ProgressBar audioProgressBar = miniPlayerCardView.findViewById(R.id.audioProgressBar);

    playerControlView.setProgressUpdateListener((position, bufferedPosition) -> {
        int progressBarPosition = (int) ((position*100)/player.getDuration());
        int bufferedProgressBarPosition = (int) ((bufferedPosition*100)/player.getDuration());
        audioProgressBar.setProgress(progressBarPosition);
        audioProgressBar.setSecondaryProgress(bufferedProgressBarPosition);
    });

我也有这个问题,我找到了解决办法

但是解决方案:

1.创建如下类:

   public class ProgressTracker implements Runnable {

        public interface PositionListener{
            public void progress(long position);
        }
    
        private final Player player;
        private final Handler handler;
        private PositionListener positionListener;
    
        public ProgressTracker(Player player, PositionListener positionListener) {
            this.player = player;
            this.positionListener = positionListener;
            handler = new Handler();
            handler.post(this);
        }
    
        public void run() {
            long position = player.getCurrentPosition();
            positionListener.progress(position);
            handler.postDelayed(this, 1000);
        }
    
        public void purgeHandler() {
            handler.removeCallbacks(this);
        }
    }
2.最后在代码中使用它:

tracker = new ProgressTracker(player, new ProgressTracker.PositionListener() {
        @Override
        public void progress(long position) {
            Log.i(TAG, "VideoViewActivity/progress: position=" + position);
        }
    });
3.在最后一步中,当您想要释放玩家时,不要忘记呼叫purgeHandler(重要)


我是通过kotlin flow做的

private fun audioProgress(exoPlayer: SimpleExoPlayer?) = flow<Int> {
        while (true) {
            emit(((exoPlayer?.currentPosition?.toFloat()?.div(exoPlayer.duration.toFloat())?.times(100))?.toInt()!!))
            delay(1000)
        }
    }.flowOn(Dispatchers.IO)

rx java实现:

private val disposablesVideoControlsDisposable = CompositeDisposable()

fun showVideoControlsAndSimilarTray() {
    videoSeekBar?.setOnSeekBarChangeListener(object :
        SeekBar.OnSeekBarChangeListener {
        override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
            if (fromUser) seekVideoProgress(progress)
        }

        override fun onStartTrackingTouch(seekBar: SeekBar?) {}
        override fun onStopTrackingTouch(seekBar: SeekBar?) {}

    })
    val disposable = Observable.interval(0, 1, TimeUnit.SECONDS)
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe {
            calculateVideoProgress()
        }
    disposablesVideoControlsDisposable.add(disposable)
}

private fun calculateVideoProgress() {
    val currentMill = exoPlayer.currentPosition
    val totalMillis = exoPlayer.duration
    if (totalMillis > 0L) {
        val remainMillis = (totalMillis - currentMill).toFloat() / 1000
        val remainMins = (remainMillis / 60).toInt()
        val remainSecs = (remainMillis % 60).toInt()
        videoProgressText.setText("$remainMins:${String.format("%02d", remainSecs)}")
        seekBarProgress.set((currentMill.toFloat() / totalMillis * 100).toInt())
    }
    
}

private fun seekVideoProgress(progress: Int) {
    val seekMillis = exoPlayer.duration.toFloat() * progress / 100
    exoPlayer.seekTo(seekMillis.toLong())
}
最后,当您完成时:

   fun disposeVideoControlsObservable() {
    disposablesVideoControlsDisposable.clear()
}
很简单

var player = SimpleExoPlayer.Builder(context).build();
player.addListener(object:Player.Listener{
     override fun onEvents(player: Player, events: Player.Events) {
        super.onEvents(player, events)
                if (events.containsAny(
                Player.EVENT_IS_LOADING_CHANGED,
                Player.EVENT_PLAYBACK_STATE_CHANGED,
                Player.EVENT_PLAY_WHEN_READY_CHANGED,
                Player.EVENT_IS_PLAYING_CHANGED
              )) {
                   log(msg="progres ${player.currentPosition}") 
               }
     }

})

您可以在1356行查看com.google.android.exoplayer2.ui.PlayerControlView.java

您可以提供关于您的解决方案的更好的描述吗?我希望这会有所帮助。这并不能回答任何问题,这实际上意味着您正在轮询state@Thomas这实际上似乎是一种正确的解决方案,因为exoplayer本身对UI生成进度事件的频率太高。@AnkitAggarwal我有自定义进度条如何在播放视频plz Help时更新进度?从今天开始,exoplayer 2.14.0版的上述方法已经改变了很多,发现很难获得用于拖动的等效方法/变量progressBarValue,…谢谢你的回答它是有效的…但它是
tracker.purgeHandler();
player.release();
player = null;
private fun audioProgress(exoPlayer: SimpleExoPlayer?) = flow<Int> {
        while (true) {
            emit(((exoPlayer?.currentPosition?.toFloat()?.div(exoPlayer.duration.toFloat())?.times(100))?.toInt()!!))
            delay(1000)
        }
    }.flowOn(Dispatchers.IO)
val audioProgressJob = launch {
            audioProgress(exoPlayer).collect {
                MP_progress_bar.progress = it
            }
        }
private val disposablesVideoControlsDisposable = CompositeDisposable()

fun showVideoControlsAndSimilarTray() {
    videoSeekBar?.setOnSeekBarChangeListener(object :
        SeekBar.OnSeekBarChangeListener {
        override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
            if (fromUser) seekVideoProgress(progress)
        }

        override fun onStartTrackingTouch(seekBar: SeekBar?) {}
        override fun onStopTrackingTouch(seekBar: SeekBar?) {}

    })
    val disposable = Observable.interval(0, 1, TimeUnit.SECONDS)
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe {
            calculateVideoProgress()
        }
    disposablesVideoControlsDisposable.add(disposable)
}

private fun calculateVideoProgress() {
    val currentMill = exoPlayer.currentPosition
    val totalMillis = exoPlayer.duration
    if (totalMillis > 0L) {
        val remainMillis = (totalMillis - currentMill).toFloat() / 1000
        val remainMins = (remainMillis / 60).toInt()
        val remainSecs = (remainMillis % 60).toInt()
        videoProgressText.setText("$remainMins:${String.format("%02d", remainSecs)}")
        seekBarProgress.set((currentMill.toFloat() / totalMillis * 100).toInt())
    }
    
}

private fun seekVideoProgress(progress: Int) {
    val seekMillis = exoPlayer.duration.toFloat() * progress / 100
    exoPlayer.seekTo(seekMillis.toLong())
}
   fun disposeVideoControlsObservable() {
    disposablesVideoControlsDisposable.clear()
}
var player = SimpleExoPlayer.Builder(context).build();
player.addListener(object:Player.Listener{
     override fun onEvents(player: Player, events: Player.Events) {
        super.onEvents(player, events)
                if (events.containsAny(
                Player.EVENT_IS_LOADING_CHANGED,
                Player.EVENT_PLAYBACK_STATE_CHANGED,
                Player.EVENT_PLAY_WHEN_READY_CHANGED,
                Player.EVENT_IS_PLAYING_CHANGED
              )) {
                   log(msg="progres ${player.currentPosition}") 
               }
     }

})