はじめに
新しいライブラリやAPIをチェックしていると、実務で使うかどうかは別として仕組みとして面白いなと思うものが出てきます。
Media3 の PreloadManager もそのひとつで、次に使いそうなメディアを先読みしておける仕組みです。
「スクロール直後に動画が滑らかに動く体験」を実装するためのコンポーネントですが、先読みやリソース共有の考え方そのものは他分野にも応用できそうだったので、基本的な使い方を簡単にまとめてみたいと思います。
Step 1. 依存関係を追加
dependencies {
implementation("androidx.media3:media3-exoplayer:<latest>")
implementation("androidx.media3:media3-ui:<latest>")
}
Step 2. Builderで生成する
PreloadManagerとExoPlayerを同じ条件で作成するのがポイントです。
val preloadManager = DefaultPreloadManager.Builder(context)
.setBandwidthMeter(DefaultBandwidthMeter.Builder(context).build())
.setRenderersFactory(DefaultRenderersFactory(context))
.setLoadControl(DefaultLoadControl())
.build()
val player = preloadManager.buildPlayer()
Step 3. アイテムを追加して先読み
val item = MediaItem.fromUri("https://example.com/video.mp4")
// 先読み
preloadManager.add(item)
// 再生
val preloaded = preloadManager.getMediaSource(item)
player.setMediaSource(preloaded)
player.prepare()
player.playWhenReady = true
Step 4. スクロールに合わせて管理
ウィンドウ外のアイテムは remove()
して、OOMを防ぎます。
fun onScrollTo(index: Int, items: List<MediaItem>) {
val window = (index-2..index+2).mapNotNull { items.getOrNull(it) }
preloadManager.setCurrentPlayingIndex(index)
preloadManager.invalidate()
// 古いものは削除
items.forEachIndexed { i, item ->
if (i !in index-2..index+2) preloadManager.remove(item)
}
}
Step 5. 結果を受け取る
preloadManager.addListener(object : PreloadManagerListener {
override fun onCompleted(item: MediaItem) {
Log.d("Preload", "success: ${item.mediaId}")
}
override fun onError(error: PreloadException) {
Log.e("Preload", "error: ${error.message}")
}
})
まとめ
- PreloadManagerを使うと、スクロール直後に再生が始まる体験を簡単に実装できる
- ExoPlayerと同じ部品を共有して作るのが安定化のポイント
- スライディングウィンドウ+Listenerでメモリ管理と改善がしやすくなる
動画リストUIを作る際はぜひ試してみてください。
さいごに
だいぶ涼しくなってきて過ごしやすい反面、久しぶりに風邪をひいてしまいました…。
季節の変わり目は体調を崩しやすいので、みなさんもどうぞご自愛ください。