首页 > 解决方案 > Exo播放器在recyclerview中使用时变黑并停止

问题描述

我有带有 Exoplayer 实例的 recyclerview。recyclerview 已设置为每页 1 个视频(全屏),可滚动。

当我滚动 10 到 12 个视频时它变黑并出现错误 MediaCodecRenderer$DecoderInitializationException

这是我的recyclerview代码。

  @Override
    public void onBindViewHolder(final Home_Adapter.CustomViewHolder holder, final int i) {
        final Home_Get_Set item = dataList.get(i);
        holder.setIsRecyclable(false);

        try {


            //to avoid refreshing player when notifyDataStateChanged() called
            if(holder.playerview.getPlayer() != null)
            {
                return;
            }


            int MIN_BUFFER_DURATION = 2000;

            int MAX_BUFFER_DURATION = 5000;

            int MIN_PLAYBACK_START_BUFFER = 1500;

            int MIN_PLAYBACK_RESUME_BUFFER = 2000;

            LoadControl loadControl = new DefaultLoadControl.Builder()
                    .setAllocator(new DefaultAllocator(true, 16))
                    .setBufferDurationsMs(MIN_BUFFER_DURATION,
                            MAX_BUFFER_DURATION,
                            MIN_PLAYBACK_START_BUFFER,
                            MIN_PLAYBACK_RESUME_BUFFER)
                    .setTargetBufferBytes(-1)
                    .setPrioritizeTimeOverSizeThresholds(true).createDefaultLoadControl();


            final SimpleExoPlayer player = new SimpleExoPlayer.Builder(context).setLoadControl(loadControl).build();

            DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context,
                    Util.getUserAgent(context, "myapp"));

            MediaSource videoSource = new ProgressiveMediaSource.Factory(dataSourceFactory)
                    .createMediaSource(Uri.parse(item.video_url));

            Log.d("resp", item.video_url);


            player.prepare(videoSource);

            player.setPlayWhenReady(false);
            player.setRepeatMode(Player.REPEAT_MODE_ALL);

           holder.playerview.setPlayer(player);




        } catch (Exception e) {

        }
    }



  @Override
    public void onViewRecycled(@NonNull CustomViewHolder holder) {
        int position = holder.getAdapterPosition();
        if (holder.playerview.getPlayer() != null) {
            holder.playerview.getPlayer().release();
        }
        super.onViewRecycled(holder);
    }

    @Override
    public void onViewAttachedToWindow(@NonNull CustomViewHolder holder) {
        super.onViewAttachedToWindow(holder);
        try {
            holder.playerview.getPlayer().setPlayWhenReady(true);
        } catch (Exception e) {

        }
    }

    @Override
    public void onViewDetachedFromWindow(@NonNull CustomViewHolder holder) {
        super.onViewDetachedFromWindow(holder);
        try {
            holder.playerview.getPlayer().setPlayWhenReady(false);
            holder.playerview.getPlayer().release();
            holder.playerview.setPlayer(null);
        } catch (Exception e) {

        }

    }

看起来 exoplayer 限制了它的实例数量。或者有什么好的方法可以在 recyclerview 中创建视频列表

标签: androidandroid-recyclerviewexoplayer

解决方案


为 exo 播放器使用全局类

class ExoClient {

    companion object {
        private lateinit var savedHolder : ExplorePostsAdapter.ViewHolder
        private var exoPlayer: SimpleExoPlayer? = null

        @Synchronized
        fun play(
            context: Context,
            string: String,
            player: ExplorePostsAdapter.ViewHolder
        ): SimpleExoPlayer? {

            try {
                savedHolder.exo.player!!.playWhenReady = false
                savedHolder.exo.player!!.stop()
            }catch (E:Exception){}

            exoPlayer = SimpleExoPlayer.Builder(context).build()
            exoPlayer!!.repeatMode = Player.REPEAT_MODE_ONE
            player.exo.player = exoPlayer

            val userAgent = Util.getUserAgent(context, context.getString(R.string.app_name.toInt()))
            val defDataSourceFactory = DefaultDataSourceFactory(context, userAgent)
            Log.d("link",string)
            val uriOfContentUrl = Uri.parse(string)
            val mediaSource: MediaSource =
                ProgressiveMediaSource.Factory(defDataSourceFactory).createMediaSource(
                    uriOfContentUrl
                )

            exoPlayer!!.prepare(mediaSource!!, true, false)
            exoPlayer!!.playWhenReady = true
            player.exo.player!!.setVolume(BaseActivity.VOLUME);

            exoPlayer!!.addListener(object : Player.Listener {
                override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
                    if (playWhenReady && playbackState == Player.STATE_READY) {
                        // media actually playing
                    } else if (playWhenReady) {
                        // might be idle (plays after prepare()),
                        // buffering (plays when data available)
                        // or ended (plays when seek away from end)
                    } else {
                        // player paused in any state

                    }
                }


                override fun onPlayerError(error: ExoPlaybackException) {
                    player.problem.visibility = View.VISIBLE


                    when (error.type) {
                        ExoPlaybackException.TYPE_SOURCE -> {
                            Log.e(
                                ContentValues.TAG,
                                "TYPE_SOURCE: " + error.sourceException.message
                            )
                        }
                        ExoPlaybackException.TYPE_RENDERER -> Log.e(
                            ContentValues.TAG, "TYPE_RENDERER: " + error.rendererException.message
                        )
                        ExoPlaybackException.TYPE_UNEXPECTED -> Log.e(
                            ContentValues.TAG,
                            "TYPE_UNEXPECTED: " + error.unexpectedException.message
                        )
                        ExoPlaybackException.TYPE_REMOTE -> {

                        }
                    }
                }
            })

            savedHolder = player
            return exoPlayer
        }
    }
}

这部分确保在新玩家开始之前停止之前的玩家

            try {
                savedHolder.exo.player!!.playWhenReady = false
                savedHolder.exo.player!!.stop()
            }catch (E:Exception){}

然后在你的 recyclerview 适配器中这样调用它

    ExoClient.play(ctx, CONTENT_URL!!,holder)

播放下一个项目,你可以使用

override fun onAttachedToRecyclerView(@NonNull recyclerView: RecyclerView) {
    super.onAttachedToRecyclerView(recyclerView)

    val manager: RecyclerView.LayoutManager = recyclerView.layoutManager!!
    if (manager is LinearLayoutManager && itemCount > 0) {
        val llm: LinearLayoutManager = manager
        recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                val visiblePosition: Int = llm.findFirstCompletelyVisibleItemPosition()
                Log.d("vmposition", visiblePosition.toString())
                if (visiblePosition != -1) {
                    if(currentPos != visiblePosition){
                        val holder: ViewHolder = recyclerView.findViewHolderForAdapterPosition(visiblePosition) as ViewHolder
                        positionHolder = holder
                        startPlayer(holder)
                    }
                    currentPos = visiblePosition
                }
            }

            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
            }
        })
    }

}

如果这有任何问题,请告诉我


推荐阅读