ExoPlayer版本更新后RxJava2调用出现Player线程访问错误
问题原因
ExoPlayer新版本强化了线程安全校验,所有Player实例的状态访问(包括getCurrentPosition())必须在主线程执行。之前的版本线程检查不严格,所以用RxJava Observable.interval默认的计算线程(RxComputationThreadPool)调用没问题,但新版本触发了线程校验逻辑,抛出IllegalStateException。
修复方案
有两种靠谱的修复方式,推荐优先用第二种:
方式一:调整RxJava线程调度,确保在主线程访问Player
修改RxJava的线程调度,先切到主线程获取播放位置,再根据需求切换线程处理结果:
// 仅更新UI的场景,直接在主线程处理 Observable.interval(100, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) // 强制切换到主线程访问Player .subscribe(tick -> { long currentPos = exoPlayer.getCurrentPosition(); // 直接在主线程更新进度UI progressBar.setProgress((int) currentPos); }); // 如果需要后续在计算线程处理逻辑的场景 Observable.interval(100, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) .map(tick -> exoPlayer.getCurrentPosition()) .observeOn(Schedulers.computation()) .subscribe(position -> { // 这里做计算逻辑 long processedPos = position / 1000; // 更新UI必须切回主线程 runOnUiThread(() -> progressText.setText(processedPos + "s")); });
方式二:改用ExoPlayer原生监听(推荐)
放弃RxJava定时轮询的方式,改用ExoPlayer自带的状态监听机制,这些回调默认在主线程触发,无需手动处理线程,效率也更高(轮询是被动拉取,监听是主动推送):
// 实现Player.Listener接口(ExoPlayer新版本的监听API) exoPlayer.addListener(new Player.Listener() { @Override public void onPositionDiscontinuity(@NonNull PositionInfo oldPos, @NonNull PositionInfo newPos, int reason) { // 位置变化时自动回调,直接获取位置更新UI long currentPos = exoPlayer.getCurrentPosition(); updateProgressUI(currentPos); } // 也可以结合播放状态变化,比如播放/暂停时更新 @Override public void onPlaybackStateChanged(int playbackState) { if (playbackState == Player.STATE_READY) { long currentPos = exoPlayer.getCurrentPosition(); updateProgressUI(currentPos); } } });
临时应急方案(不推荐)
ExoPlayer提供了允许非主线程调用的重载方法,但这种方式绕过了线程安全校验,可能引发潜在的并发问题,仅适合临时调试:
// 参数allowNonBlocking设为true,允许非主线程调用 long currentPos = exoPlayer.getCurrentPosition(true);
内容的提问来源于stack exchange,提问作者onesector
相关产品推荐
相关产品推荐

