Android Media3(ExoPlayer):如何设置Timeline中Window的defaultPositionUs?
给Media3播放列表项设置默认起始位置(恢复上次播放进度)
首先明确:Timeline.Window.defaultPositionUs是只读属性,无法直接设置,它是Player根据MediaItem的配置或存储的进度自动计算得出的。要实现播放列表项自动切换时从上次中断处恢复,有以下几种可行方案:
方案一:给每个MediaItem单独配置起始位置
在构建MediaItem时,直接通过MediaItem.Builder指定起始位置,Player加载该MediaItem时会自动从指定位置开始播放。
示例代码:
// 假设你已保存了每个媒体的上次播放位置(单位:毫秒) val savedPositions = mapOf( "media_id_1" to 15000L, // 第一个MP3上次播放到15秒 "media_id_2" to 30000L // 第二个MP3上次播放到30秒 ) // 构建带起始位置的MediaItem列表 val mediaItems = listOf( MediaItem.Builder() .setUri("https://example.com/song1.mp3") .setMediaId("media_id_1") .setStartPositionMs(savedPositions["media_id_1"] ?: 0) .build(), MediaItem.Builder() .setUri("/storage/emulated/0/song2.mp3") .setMediaId("media_id_2") .setStartPositionMs(savedPositions["media_id_2"] ?: 0) .build() ) // 设置播放列表 player.setMediaItems(mediaItems) player.prepare()
方案二:利用Media3的进度存储机制(推荐)
Media3提供了MediaItemMetadataStore接口,可自动保存和读取每个MediaItem的播放进度,无需手动管理每个item的起始位置配置。
1. 实现简单的MetadataStore
用SharedPreferences实现自定义存储:
class SharedPrefMetadataStore(private val context: Context) : MediaItemMetadataStore { private val prefs = context.getSharedPreferences("media_progress", Context.MODE_PRIVATE) override fun getMetadata(mediaItem: MediaItem): MediaItemMetadata? { val position = prefs.getLong(mediaItem.mediaId, 0) return MediaItemMetadata.Builder() .setPlaybackPositionMs(position) .build() } override fun updateMetadata(mediaItem: MediaItem, metadata: MediaItemMetadata) { prefs.edit() .putLong(mediaItem.mediaId, metadata.playbackPositionMs) .apply() } }
2. 给Player配置MetadataStore
初始化Player时传入自定义存储实例:
val player = ExoPlayer.Builder(context) .setMediaItemMetadataStore(SharedPrefMetadataStore(context)) .build() // 设置播放列表后,Player会自动读取每个item的保存进度 player.setMediaItems(mediaItems) player.prepare()
这种方案下,Player会在播放暂停/切换时自动保存当前item的进度,下次加载该item时自动从上次位置恢复,完全适配播放列表自动切换的场景。
方案三:播放列表切换时手动设置位置
如果需要更精细的控制,可以监听Player的MediaItemTransitionListener,在切换到新的MediaItem时手动设置起始位置:
player.addMediaItemTransitionListener(object : MediaItemTransitionListener { override fun onMediaItemTransition( mediaItem: MediaItem?, reason: Int ) { mediaItem?.let { val savedPosition = getSavedPosition(it.mediaId) // 自定义方法获取保存的进度 player.seekTo(savedPosition) } } })
内容的提问来源于stack exchange,提问作者Akshdeep Singh
相关产品推荐
相关产品推荐

