android - 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 中创建视频列表
解决方案
为 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)
}
})
}
}
如果这有任何问题,请告诉我