Skip to content

Commit d1b418e

Browse files
authored
Add PreloadManager snippets, and update media3 to 1.8.0 (#574)
* Adding PreloadManager doc snippets Adding snippets to support new PreloadManager docs. That requires bumping the Media3 version up to 1.8.0. Separate CL is in play to update developer.android.com to pull the snippets in from Github.
1 parent 910e372 commit d1b418e

File tree

3 files changed

+141
-1
lines changed

3 files changed

+141
-1
lines changed

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ maps-compose = "6.6.0"
5757
material = "1.14.0-alpha02"
5858
material3-adaptive = "1.1.0"
5959
material3-adaptive-navigation-suite = "1.3.2"
60-
media3 = "1.7.1"
60+
media3 = "1.8.0"
6161
# @keep
6262
minSdk = "35"
6363
okHttp = "4.12.0"

misc/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ dependencies {
5757
implementation(libs.androidx.compose.ui.util)
5858
implementation(libs.androidx.compose.ui.tooling.preview)
5959
implementation(libs.androidx.compose.material3)
60+
implementation(libs.androidx.media3.common)
61+
implementation(libs.androidx.media3.exoplayer)
6062
implementation(libs.androidx.tracing)
6163

6264
implementation(libs.hilt.android)
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*
2+
* Copyright 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.snippets
18+
19+
import android.os.Bundle
20+
import androidx.annotation.OptIn
21+
import androidx.appcompat.app.AppCompatActivity
22+
import androidx.media3.common.C
23+
import androidx.media3.common.MediaItem
24+
import androidx.media3.common.util.UnstableApi
25+
import androidx.media3.exoplayer.ExoPlayer
26+
import androidx.media3.exoplayer.source.preload.DefaultPreloadManager
27+
import androidx.media3.exoplayer.source.preload.TargetPreloadStatusControl
28+
import java.lang.Math.abs
29+
30+
// constants to make the code snippets work
31+
const val currentPlayingIndex = 10
32+
33+
@UnstableApi
34+
// [START android_defaultpreloadmanager_MyTargetPreloadStatusControl]
35+
class MyTargetPreloadStatusControl(
36+
currentPlayingIndex: Int = C.INDEX_UNSET
37+
) : TargetPreloadStatusControl<Int, DefaultPreloadManager.PreloadStatus> {
38+
39+
override fun getTargetPreloadStatus(index: Int): DefaultPreloadManager.PreloadStatus? {
40+
if (index - currentPlayingIndex == 1) { // next track
41+
// return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED and
42+
// suggest loading 3000ms from the default start position
43+
return DefaultPreloadManager.PreloadStatus.specifiedRangeLoaded(3000L)
44+
} else if (index - currentPlayingIndex == -1) { // previous track
45+
// return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED and
46+
// suggest loading 3000ms from the default start position
47+
return DefaultPreloadManager.PreloadStatus.specifiedRangeLoaded(3000L)
48+
} else if (abs(index - currentPlayingIndex) == 2) {
49+
// return a PreloadStatus that is labelled by STAGE_TRACKS_SELECTED
50+
return DefaultPreloadManager.PreloadStatus.TRACKS_SELECTED
51+
} else if (abs(index - currentPlayingIndex) <= 4) {
52+
// return a PreloadStatus that is labelled by STAGE_SOURCE_PREPARED
53+
return DefaultPreloadManager.PreloadStatus.SOURCE_PREPARED
54+
}
55+
return null
56+
}
57+
}
58+
// [END android_defaultpreloadmanager_MyTargetPreloadStatusControl]
59+
60+
class PreloadManagerSnippetsKotlin {
61+
62+
class PreloadSnippetsActivity : AppCompatActivity() {
63+
private val context = this
64+
65+
@OptIn(UnstableApi::class)
66+
override fun onCreate(savedInstanceState: Bundle?) {
67+
super.onCreate(savedInstanceState)
68+
69+
// [START android_defaultpreloadmanager_createPLM]
70+
val targetPreloadStatusControl = MyTargetPreloadStatusControl()
71+
val preloadManagerBuilder =
72+
DefaultPreloadManager.Builder(context, targetPreloadStatusControl)
73+
val preloadManager = preloadManagerBuilder.build()
74+
// [END android_defaultpreloadmanager_createPLM]
75+
76+
val player = preloadManagerBuilder.buildExoPlayer()
77+
78+
// [START android_defaultpreloadmanager_addMedia]
79+
val initialMediaItems = pullMediaItemsFromService(/* count= */ 20)
80+
for (index in 0 until initialMediaItems.size) {
81+
preloadManager.add(initialMediaItems.get(index), /* rankingData= */ index)
82+
}
83+
// items aren't actually loaded yet! need to call invalidate() after this
84+
// [END android_defaultpreloadmanager_addMedia]
85+
86+
// [START android_defaultpreloadmanager_invalidate]
87+
preloadManager.invalidate()
88+
// [END android_defaultpreloadmanager_invalidate]
89+
}
90+
91+
@OptIn(UnstableApi::class)
92+
private fun fetchMedia(
93+
preloadManager: DefaultPreloadManager,
94+
mediaItem: MediaItem,
95+
player: ExoPlayer,
96+
currentIndex: Int
97+
) {
98+
// [START android_defaultpreloadmanager_getAndPlayMedia]
99+
// When a media item is about to display on the screen
100+
val mediaSource = preloadManager.getMediaSource(mediaItem)
101+
if (mediaSource != null) {
102+
player.setMediaSource(mediaSource)
103+
} else {
104+
// If mediaSource is null, that mediaItem hasn't been added to the preload manager
105+
// yet. So, send it directly to the player when it's about to play
106+
player.setMediaItem(mediaItem)
107+
}
108+
player.prepare()
109+
110+
// When the media item is displaying at the center of the screen
111+
player.play()
112+
preloadManager.setCurrentPlayingIndex(currentIndex)
113+
114+
// Need to call invalidate() to update the priorities
115+
preloadManager.invalidate()
116+
// [END android_defaultpreloadmanager_getAndPlayMedia]
117+
}
118+
119+
@OptIn(UnstableApi::class)
120+
private fun removeMedia(mediaItem: MediaItem, preloadManager: DefaultPreloadManager) {
121+
// [START android_defaultpreloadmanager_removeItem]
122+
preloadManager.remove(mediaItem)
123+
// [END android_defaultpreloadmanager_removeItem]
124+
}
125+
126+
@OptIn(UnstableApi::class)
127+
private fun releasePLM(preloadManager: DefaultPreloadManager) {
128+
// [START android_defaultpreloadmanager_releasePLM]
129+
preloadManager.release()
130+
// [END android_defaultpreloadmanager_releasePLM]
131+
}
132+
133+
// dummy methods to support the code snippets
134+
private fun pullMediaItemsFromService(count: Int): List<MediaItem> {
135+
return listOf()
136+
}
137+
}
138+
}

0 commit comments

Comments
 (0)