【问题标题】:ExoPlayer 2 Playlist ListenerExoPlayer 2 播放列表监听器
【发布时间】:2017-03-10 03:32:25
【问题描述】:

我正在使用 ExoPlayer 2.x 的新功能来播放这样的音频文件列表:

List<MediaSource> playlist = new ArrayList<>();

...

ConcatenatingMediaSource concatenatedSource = new ConcatenatingMediaSource(
            playlist.toArray(new MediaSource[playlist.size()]));

mExoPlayer.prepare(concatenatedSource);
mExoPlayer.setPlayWhenReady(true);

这工作正常,但为了相应地更新我的 UI,我需要知道当前正在播放的曲目以及该曲目的进度。 ExoPlayer 有听众吗?

谢谢!

【问题讨论】:

  • 你有没有得到这个答案?如 cmets 所述,接受的答案没有帮助。

标签: android exoplayer


【解决方案1】:

由于这里的答案对我不起作用,我将在 Kotlin 中添加我的工作解决方案。 从那时起,也有很多方法被弃用了。

您可以在创建播放列表时通过设置 mediaId 来跟踪当前曲目(视频)

分级:

implementation 'com.google.android.exoplayer:exoplayer:2.14.1'

布局xml:

<com.google.android.exoplayer2.ui.PlayerView
    android:id="@+id/player_view"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    app:show_buffering="when_playing"/>

代码:

private lateinit var exoPlayer: SimpleExoPlayer
private lateinit var playerView: PlayerView
private lateinit var fileList: List<FileModel>

private fun initPlayer() {
    playerView = findViewById(R.id.player_view)
    playerView.controllerShowTimeoutMs = 0
    playerView.cameraDistance = 30F
    exoPlayer = SimpleExoPlayer.Builder(this).build()
    playerView.player = exoPlayer

    setPlaylist()
    exoPlayer.prepare()
    exoPlayer.seekTo(position, C.TIME_UNSET) // position = current song or video
    exoPlayer.playWhenReady = true
    addPlayerListeners()
}

private fun setPlaylist() {
    for ((pos, file) in fileList.withIndex()) {
        val mediaItem = MediaItem.Builder().setUri(file.url).setMediaId(pos.toString()).build()
        exoPlayer.addMediaItem(mediaItem)
    }
}

private fun addPlayerListeners() {
    exoPlayer.addListener(object : Player.Listener{
        override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
            super.onMediaItemTransition(mediaItem, reason)
            val  item = mediaItem?.mediaMetadata
            val bmp = item?.artworkData
            Log.i(TAG, "position = ${mediaItem?.mediaId}")
            val currentPos = mediaItem?.mediaId
            updateViews(currentPos, bmp)
        }
    })
}

private fun updateViews(currentPos: String?, bmp: ByteArray?) {
    position = currentPos?.toInt() ?: 0
    val title = fileList[position].title
    textview_title.text = title

    if (bmp == null) {
        image_view.setImageResource(R.drawable.exo_ic_default_album_image)
        return
    }
    val bitmap = BitmapFactory.decodeByteArray(bmp, 0, bmp.size)
    image_view.setImageBitmap(bitmap)
}

【讨论】:

    【解决方案2】:

    所以我处于类似情况,需要知道播放列表中的下一个视频何时开始。我发现ExoPlayer.EventListener 有一个名为onPositionDiscontinuity() 的方法,每次视频更改或“搜索”到播放列表中的下一个时都会调用该方法。

    我没有广泛使用过这种方法,但就我目前所见,这是你应该关注的方法。触发该方法时没有传递任何参数,因此您必须保留某种计数器或队列来跟踪任何给定时刻正在播放的内容。

    希望这会有所帮助!

    编辑:Exoplayer.getCurrentWindowIndex() 返回的索引更改是 recommended way,用于检测播放列表中的项目更改 MediaSource

    int lastWindowIndex = 0; // global var in your class encapsulating exoplayer obj (Activity, etc.)
    
    exoPlayer.addListener(new ExoPlayer.EventListener() {
            @Override
            public void onLoadingChanged(boolean isLoading) {
            }
    
            @Override
            public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
            }
    
            @Override
            public void onTimelineChanged(Timeline timeline, Object manifest) {
            }
    
            @Override
            public void onPlayerError(ExoPlaybackException error) {
            }
    
            @Override
            public void onPositionDiscontinuity() {
                //THIS METHOD GETS CALLED FOR EVERY NEW SOURCE THAT IS PLAYED
                int latestWindowIndex = exoPlayer.getCurrentWindowIndex();
                if (latestWindowIndex != lastWindowIndex) {
                    // item selected in playlist has changed, handle here
                    lastWindowIndex = latestWindowIndex;
                    // ...
                }
            }
        });
    

    【讨论】:

    • 当你快进或快退时也会调用该方法..所以它对我不起作用:(我需要一个只在新视频开始时触发的监听器 B-(
    • 您可能会尝试将上述代码包装到自定义 ExoPlayer 类中。在该类中,您可以维护播放/快进/倒带正在播放的视频所需的对象,并且仅在视频正常播放时执行 onPositionDiscontinuity() 方法中的操作,而不是快进/倒带。基本上你会在 onPositionDiscontinuity() 方法中有逻辑来检查视频是快进还是快退,并且只有在这两种情况都为假时才继续。
    • 这对信息有用...非常感谢您的指导:)
    【解决方案3】:

    您可以实现以下事件并根据播放器的状态更新您的用户界面。

     mExoPlayer.addListener(new ExoPlayer.Listener() {
                @Override
                public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
                    if (playbackState == PlaybackStateCompat.STATE_PLAYING) {
                        //do something                 
                    }
                }
    
                @Override
                public void onPlayWhenReadyCommitted() {
    
                }
    
                @Override
                public void onPlayerError(ExoPlaybackException error) {
                    mExoPlayer.stop();
    
                }
            });
    

    【讨论】:

    • 我如何知道正在播放的曲目?
    • 处理此问题的一种方法是将当前播放的歌曲保存在缓存中。当播放器状态发生变化时,您可以触发一个事件以显示当前歌曲。
    • @DoronKakuli 但 onPositionDiscontinuity 在 Exoplayer 准备好播放歌曲时被调用,而不是在单击下一个按钮时调用然后如何处理和更新 UI ??
    • @timoschloesser 使用 Player.getCurrentMediaItem (exoplayer.dev/playlists.html)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-16
    • 1970-01-01
    • 2018-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多