Posted by Mayuri Khinvasara Khabya – Developer Relations Engineer (LinkedIn and X)
In in the present day’s media-centric apps, delivering a clean, uninterrupted playback expertise is vital to a pleasant consumer expertise. Customers anticipate their movies to start out immediately and play seamlessly with out pauses.
The core problem is latency. Historically, a video participant solely begins its work—connecting, downloading, parsing, buffering—after the consumer has chosen an merchandise for playback. This reactive strategy is sluggish for in the present day’s quick kind video context. The answer is to be proactive. We have to anticipate what the consumer will watch subsequent and get the content material prepared forward of time. That is the essence of preloading.
The important thing advantages of preloading embrace:
- 🚀 Quicker Playback Begin: Movies are already able to go, resulting in faster transitions between gadgets and a extra quick begin.
- 📉 Diminished Buffering: By proactively loading knowledge, playback is much much less prone to stall, for instance as a consequence of community hiccups.
- ✨ Ensuing smoother Consumer Expertise: The mix of sooner begins and fewer buffering creates a extra fluid, seamless interplay for customers to get pleasure from.
On this three-part sequence, we’ll introduce and deep dive into Media3’s highly effective utilities for (pre)loading elements.
- In Half 1, we’ll cowl the foundations: understanding the totally different preloading methods out there in Media3, enabling PreloadConfiguration and organising the DefaultPreloadManager, enabling your app to preload gadgets. By the tip of this weblog, you must be capable to preload and play media gadgets together with your configured rating and period.
- In Half 2, we’ll get into extra superior subjects of DefaultPreloadManager: utilizing listeners for analytics, exploring production-ready finest practices just like the sliding window sample and customized shared elements of DefaultPreloadManager and ExoPlayer.
- In Half 3, we’ll dive deep into disk caching with DefaultPreloadManager.
Preloading to the rescue! 🦸♀️
The core thought behind preloading is straightforward: load media content material earlier than you want it. By the point a consumer swipes to the subsequent video, the primary segments of the video are already downloaded and out there, prepared for quick playback.
Consider it like a restaurant. A busy kitchen does not anticipate an order to start out chopping onions. 🧅 They do their prep work upfront. Preloading is the prep work in your video participant.
When enabled, preloading will help decrease be a part of latency when a consumer skips to the subsequent merchandise earlier than the playback buffer reaches the subsequent merchandise. The primary interval of the subsequent window is ready and video, audio and textual content samples are buffered. The preloaded interval is later queued into the participant with buffered samples instantly out there and able to be fed to the codec for rendering.
In Media3 there are two main APIs for preloading, every fitted to totally different use instances. Choosing the proper API is step one.
1. Preloading playlist gadgets with PreloadConfiguration
That is the easy strategy, helpful for linear, sequential media like playlists the place the playback order is predictable (like a sequence of episodes). You give the participant the total checklist of media gadgets utilizing ExoPlayer’s playlist APIs and set the PreloadConfiguration for the participant, then it mechanically preloads the subsequent gadgets within the sequence as configured. This API makes an attempt to optimize the be a part of latency when a consumer skips to the subsequent merchandise earlier than the playback buffer already overlaps into the subsequent merchandise.
Preloading is barely began when no media is being loaded for the continued playback, which prevents it from competing for bandwidth with the first playback.
In case you’re nonetheless undecided whether or not you want preloading, this API is a superb low-lift choice to attempt it out!
participant.preloadConfiguration = PreloadConfiguration(/* targetPreloadDurationUs= */ 5_000_000L)
With the PreloadConfiguration above, the participant tries to preload 5 seconds of media for the subsequent merchandise within the playlist.
As soon as opted-in, playlist preloading could be turned off once more by utilizing PreloadConfiguration.DEFAULT to disable playlist preloading:
participant.preloadConfiguration = PreloadConfiguration.DEFAULT
2. Preloading dynamic lists with PreloadManager
For dynamic UIs like vertical feeds or carousels, the place the “subsequent” merchandise is set by consumer interplay, the PreloadManager API is acceptable. It is a new highly effective, standalone part inside the Media3 ExoPlayer library particularly designed to proactively preload. It manages a group of potential MediaSources, prioritizing them based mostly on proximity to the consumer’s present place and gives granular management over what to preload, appropriate for complicated eventualities like dynamic feeds of quick kind movies.
Setting Up Your PreloadManager
The DefaultPreloadManager is the canonical implementation for PreloadManager.
The builder of DefaultPreloadManager can construct each the DefaultPreloadManager and any ExoPlayer situations that may play its preloaded content material. To create a DefaultPreloadManager, you will want to cross a TargetPreloadStatusControl, which the preload supervisor can question to learn the way a lot to load for an merchandise. We are going to clarify and outline an instance of TargetPreloadStatusControl within the part under.
val preloadManagerBuilder = DefaultPreloadManager.Builder(context, targetPreloadStatusControl) val preloadManager = val preloadManagerBuilder.construct() // Construct ExoPlayer with DefaultPreloadManager.Builder val participant = preloadManagerBuilder.buildExoPlayer()
Utilizing the identical builder for each the ExoPlayer and DefaultPreloadManager is critical, which ensures that the elements below the hood of them are accurately shared.
And that is it! You now have a supervisor able to obtain directions.
Configuring Period and Rating with TargetPreloadStatusControl
What if you wish to preload, say, 10 seconds of video ? You possibly can present the place of your media gadgets within the carousel, and the DefaultPreloadManager prioritizes loading the gadgets based mostly on how shut it’s to the merchandise the consumer is presently taking part in.
If you wish to management how a lot period of the merchandise to preload, you’ll be able to inform that with DefaultPreloadManager.PreloadStatus you come back.
For instance,
- Merchandise ‘A’ is the very best precedence, load 5 seconds of video.
- Merchandise ‘B’ is medium precedence however while you get to it, load 3 seconds of video.
- Merchandise ‘C’ is much less precedence, load solely tracks.
- Merchandise ‘D’ is even much less of a precedence, simply put together.
- Every other gadgets are far-off, Don’t preload something.
This granular management will help you optimize your useful resource utilization which is beneficial for a seamless playback.
import androidx.media3.exoplayer.DefaultPreloadManager.PreloadStatus class MyTargetPreloadStatusControl( currentPlayingIndex: Int = C.INDEX_UNSET ) : TargetPreloadStatusControl<Int,PreloadStatus> { // The app is liable for updating this based mostly on UI state override enjoyable getTargetPreloadStatus(index: Int): PreloadStatus? { val distance = index - currentPlayingIndex // Adjoining gadgets (Subsequent): preload 5 seconds if (distance == 1) { // Return a PreloadStatus that's labelled by STAGE_SPECIFIED_RANGE_LOADED and recommend loading // 5000ms from the default begin place return PreloadStatus.specifiedRangeLoaded(5000L) } // Adjoining gadgets (Earlier): preload 3 seconds else if (distance == -1) { // Return a PreloadStatus that's labelled by STAGE_SPECIFIED_RANGE_LOADED //and recommend loading 3000ms from the default begin place return PreloadStatus.specifiedRangeLoaded(3000L) } // Objects two positions away: simply choose tracks else if (distance) == 2) { // Return a PreloadStatus that's labelled by STAGE_TRACKS_SELECTED return PreloadStatus.TRACKS_SELECTED } // Objects 4 positions away: simply choose put together else if (abs(distance) <= 4) { // Return a PreloadStatus that's labelled by STAGE_SOURCE_PREPARED return PreloadStatus.SOURCE_PREPARED } // All different gadgets are too far-off return null } }
Tip: PreloadManager can preserve each the earlier and subsequent gadgets preloaded, whereas the PreloadConfiguration will solely stay up for the subsequent gadgets.
Managing Preloading Objects
Along with your supervisor created, you can begin telling it what to work on. As your consumer scrolls by means of a feed, you may establish the upcoming movies and add them to the supervisor. The interplay with the PreloadManager is a state-driven dialog between your UI and the preloading engine.
1. Add Media Objects
As you populate your feed, you should inform the supervisor of the media it wants to trace. If you’re beginning, you would add the complete checklist you need to preload. Subsequently you’ll be able to preserve including a single merchandise to the checklist as and when required. You’ve full management over what gadgets are within the preloading checklist which suggests you additionally must handle what’s added and faraway from the supervisor.
val initialMediaItems = pullMediaItemsFromService(/* rely= */ 20) for (index in 0 till initialMediaItems.measurement) { preloadManager.add( initialMediaItems.get(index),index) ) }
The supervisor will now begin fetching knowledge for this MediaItem within the background.
After including, inform the supervisor to re-evaluate its new checklist (hinting that one thing has modified like including/ eradicating an merchandise, or the consumer switches to play a brand new merchandise.)
preloadManager.invalidate()
2. Retrieve and Play an Merchandise
Right here comes the principle playback logic. When the consumer decides to play that video, you needn’t create a brand new MediaSource. As an alternative, you ask the PreloadManager for the one it has already ready. You possibly can retrieve the MediaSource from the Preload Supervisor utilizing the MediaItem.
If the retrieved merchandise from the PreloadManager is null, meaning the mediaItem shouldn’t be preloaded but or added to the PreloadMamager, so that you select to set the mediaItem immediately.
// When a media merchandise is about to display on the display val mediaSource = preloadManager.getMediaSource(mediaItem) if (mediaSource!= null) { participant.setMediaSource(mediaSource) } else { // If mediaSource is null, that mediaItem hasn't been added but. // So, ship it on to the participant. participant.setMediaItem(mediaItem) } participant.put together() // When the media merchandise is displaying on the middle of the display participant.play()
By getting ready the MediaSource retrieved from the PreloadManager, you seamlessly transition from preloading to playback, utilizing the info that is already in reminiscence. That is what makes the beginning time sooner.
3. Hold the present index in sync with the UI
Since our feed / checklist might be dynamic, it is essential to inform the PreloadManager of your present taking part in index in order that it could actually all the time prioritize gadgets nearest to your present index for preloading.
preloadManager.setCurrentPlayingIndex(currentIndex) // Have to name invalidate() to replace the priorities preloadManager.invalidate()
4. Take away an Merchandise
To maintain the supervisor environment friendly, you must take away gadgets it now not wants to trace, akin to gadgets which can be far-off from the consumer’s present place.
// When an merchandise is just too removed from the present taking part in index preloadManager.take away(mediaItem)
If it is advisable clear all gadgets directly, you’ll be able to name preloadManager.reset().
5. Launch the Supervisor
If you now not want the PreloadManager (e.g., when your UI is destroyed), you should launch it to unencumber its assets. place to do that is the place you’re already releasing your Participant’s assets. It’s beneficial to launch the supervisor earlier than the participant because the participant can proceed to play for those who do not want any extra preloading.
// In your Exercise's onDestroy() or Composable's onDispose preloadManager.launch()
Demo time
Test it reside in motion 👍
Within the demo under , we see the affect of PreloadManager on the suitable facet which has sooner load instances, whereas the left facet exhibits the present expertise. You too can view the code pattern for the demo. (Bonus: It additionally shows startup latency for each video)
![Jetpack Media3 API for fast loading of short videos [PreloadManager]](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPRidTRe3s-2TIek6_YlfUsFwxRAaH-6rynAMXLX7UwVM9b-PhCAfOqAWwrTIBj6pSfntZizlYLU6nhmkNqbwwvBLGkWRjsOKNb-c56Jr8gutxBkSZidmOP1T420tBU5knaVvuAygMKHnDV8epXMc2TuIZN2klfnIKulNQUncwfz4fuuIlbLQ3yxhrhrU/s1600/Demo-PreloadManager%202.gif)
What’s Subsequent?
And that is a wrap for Half 1! You now have the instruments to construct a dynamic preloading system. You possibly can both use PreloadConfiguration to preload the subsequent merchandise of a playlist in ExoPlayer or arrange a DefaultPreloadManager, add and take away gadgets on the fly, configure the goal preload standing, and accurately retrieve the preloaded content material for playback.
In Half 2, we’ll go deeper on the DefaultPreloadManager. We’ll discover how you can hear for preloading occasions, talk about finest practices like utilizing a sliding window to keep away from reminiscence points, and peek below the hood at customized shared elements of ExoPlayer and DefaultPreloadManager.
Do you’ve any suggestions to share? We’re keen to listen to from you.
Keep tuned, and go make your app sooner! 🚀

