ExoPlayer结合LazyColumn实现Instagram Reels效果优化求助
ExoPlayer + LazyColumn 实现Reels滚动卡顿优化方案
1. PlayerView复用与状态管理优化
复用PlayerView的核心是避免重组时重复初始化,用remember缓存实例,并配合DisposableEffect处理媒体项切换的生命周期:
LazyColumn { items(videos, key = { it.id }) { video -> val playerView = remember { PlayerView(context).apply { player = exoPlayerSingleton useController = false resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL } } DisposableEffect(video) { // 切换当前媒体项 exoPlayerSingleton.setMediaItem(MediaItem.fromUri(video.uri)) exoPlayerSingleton.prepare() exoPlayerSingleton.play() onDispose { exoPlayerSingleton.pause() exoPlayerSingleton.clearMediaItems() // 释放当前媒体资源 } } playerView } }
- 必须给
items设置唯一key,确保LazyColumn能精准复用列表项 - 用
remember缓存PlayerView,仅首次创建时初始化
2. 预加载策略调整
一次性预加载所有媒体项会导致内存过载,改为滚动时动态预加载相邻项:
val listState = rememberLazyListState() LaunchedEffect(listState.firstVisibleItemIndex) { val currentIndex = listState.firstVisibleItemIndex // 仅预加载当前项的前后各1个视频 val preloadRange = (currentIndex -1)..(currentIndex +1) val targetIndices = preloadRange.filter { it in videos.indices } // 添加需要预加载的媒体项 targetIndices.forEach { index -> val mediaItem = MediaItem.fromUri(videos[index].uri) if (!exoPlayerSingleton.mediaItems.any { it.mediaId == video.id }) { exoPlayerSingleton.addMediaItem(mediaItem) } } // 移除超出预加载范围的旧媒体项 val removeIndices = exoPlayerSingleton.mediaItems.indices.filter { it < currentIndex -2 || it > currentIndex +2 } removeIndices.reversed().forEach { exoPlayerSingleton.removeMediaItem(it) } }
3. ExoPlayer性能参数调优
调整缓冲策略和渲染配置,减少加载延迟与资源占用:
// 自定义缓冲配置,降低首次加载门槛 val loadControl = DefaultLoadControl.Builder() .setBufferDurationsMs( 1500, // 最小缓冲时长 4000, // 最大缓冲时长 800, // 播放前需缓冲的时长 800 // 缓冲不足时的重试间隔 ) .build() // 初始化单例Player时应用配置 val exoPlayerSingleton = remember { ExoPlayer.Builder(context) .setLoadControl(loadControl) .setVideoScalingMode(C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING) .build() }
- 关闭不需要的监听(如
videoFrameMetadataListener),减少主线程回调 - 若设备硬件加速兼容性差,可尝试禁用:
playerView.useHardwareAcceleration = false
4. LazyColumn滚动优化
- 禁用不必要的过度滚动效果,减少UI绘制开销:
LazyColumn( state = listState, modifier = Modifier.overScroll(OverScrollBehavior.None) ) { // ... 列表项逻辑 }
- 避免在列表项中执行复杂计算或IO操作,所有数据预处理提前完成
5. 资源释放机制完善
确保页面销毁时彻底释放Player资源,避免内存泄漏:
DisposableEffect(Unit) { onDispose { exoPlayerSingleton.stop() exoPlayerSingleton.release() } }
- 给PlayerView添加生命周期监听,确保页面不可见时暂停播放:
playerView.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View?) { exoPlayerSingleton.play() } override fun onViewDetachedFromWindow(v: View?) { exoPlayerSingleton.pause() } })
内容的提问来源于stack exchange,提问作者bhavin vala
相关产品推荐
相关产品推荐

