{"id":347804,"date":"2025-09-05T15:33:38","date_gmt":"2025-09-05T20:33:38","guid":{"rendered":"https:\/\/michigandigitalnews.com\/index.php\/2025\/09\/05\/android-developers-blog-elevating-media-playback-introducing-preloading-with-media3\/"},"modified":"2025-09-05T15:33:38","modified_gmt":"2025-09-05T20:33:38","slug":"android-developers-blog-elevating-media-playback-introducing-preloading-with-media3","status":"publish","type":"post","link":"https:\/\/michigandigitalnews.com\/index.php\/2025\/09\/05\/android-developers-blog-elevating-media-playback-introducing-preloading-with-media3\/","title":{"rendered":"Android Developers Blog: Elevating media playback: Introducing preloading with Media3"},"content":{"rendered":"<p> [ad_1]<br \/>\n<\/p>\n<div>\n<meta content=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEi3xfaeSVwhItxPTRdI2vEUu6t8ZSJWKMYB6xWkb9inI8ab1GltWuCExl29Z8SAQ1Fo2A4moEQLykBdkjIZ_IqikrD-QrmkwWKCOaKALh5fMiV5SRRUM7JRmjavEZ64horigEBxNK5RtW_NI88_LjbqTa69Os3a-ADQbrNp7R5e78dXmkc7rsYyx3cRYdo\/s1600\/AndroidSpotlight_Camera&amp;Media_Blog_Media3%201.5.0_Card%20%281%29.png\" name=\"twitter:image\"\/><br \/>\n<img decoding=\"async\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEi3xfaeSVwhItxPTRdI2vEUu6t8ZSJWKMYB6xWkb9inI8ab1GltWuCExl29Z8SAQ1Fo2A4moEQLykBdkjIZ_IqikrD-QrmkwWKCOaKALh5fMiV5SRRUM7JRmjavEZ64horigEBxNK5RtW_NI88_LjbqTa69Os3a-ADQbrNp7R5e78dXmkc7rsYyx3cRYdo\/s1600\/AndroidSpotlight_Camera&amp;Media_Blog_Media3%201.5.0_Card%20%281%29.png\" style=\"display: none;\"\/><\/p>\n<p><em>Posted by Mayuri Khinvasara Khabya &#8211; Developer Relations Engineer (<a href=\"https:\/\/www.linkedin.com\/in\/mayurikhinvasara\" target=\"_blank\" rel=\"noopener\">LinkedIn<\/a> and <a href=\"https:\/\/x.com\/mayuri_k\" target=\"_blank\" rel=\"noopener\">X<\/a>)<\/em><\/p>\n<p><a href=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEh1PmhSCIphw3wGW7dJ9Yr7LLgG_6rqNwklO04UO6iZAsh6HjosgOn_SovJ8sEJvNYdeU08nMgnHQ3_L8F3pNU0Z72viRxqg8Ir0ceP-XVx45lkfImCbLnKywl7lho5CWJt0hBqt5dehuzLLpkrmkHdpTXRCzokmV4m3lswrsxAHWRHCstygUnK5PKCrO4\/s1600\/AndroidSpotlight_Camera&amp;Media_Blog_Media3%201.5.0_Banner.png\"><img decoding=\"async\" border=\"0\" data-original-height=\"800\" data-original-width=\"100%\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEh1PmhSCIphw3wGW7dJ9Yr7LLgG_6rqNwklO04UO6iZAsh6HjosgOn_SovJ8sEJvNYdeU08nMgnHQ3_L8F3pNU0Z72viRxqg8Ir0ceP-XVx45lkfImCbLnKywl7lho5CWJt0hBqt5dehuzLLpkrmkHdpTXRCzokmV4m3lswrsxAHWRHCstygUnK5PKCrO4\/s1600\/AndroidSpotlight_Camera&amp;Media_Blog_Media3%201.5.0_Banner.png\"\/><\/a><\/p>\n<p align=\"justify\">In today&#8217;s media-centric apps, delivering a smooth, uninterrupted playback experience is key to a delightful user experience. Users expect their videos to start instantly and play seamlessly without pauses.<\/p>\n<p align=\"justify\">The core challenge is latency. Traditionally, a video player only starts its work\u2014connecting, downloading, parsing, buffering\u2014after the user has chosen an item for playback. This reactive approach is slow for today&#8217;s short form video context. The solution is to be proactive. We need to anticipate what the user will watch next and get the content ready ahead of time. This is the essence of preloading.<\/p>\n<p>The key benefits of preloading include:<\/p>\n<ul>\n<ul>\n<li align=\"justify\"><b>\ud83d\ude80 Faster Playback Start:<\/b> Videos are already ready to go, leading to quicker transitions between items and a more immediate start.<\/li>\n<li align=\"justify\"><b>\ud83d\udcc9 Reduced Buffering:<\/b> By proactively loading data, playback is far less likely to stall, for example due to network hiccups.<\/li>\n<li align=\"justify\"><b>\u2728 Resulting  smoother User Experience:<\/b> The combination of faster starts and less buffering creates a more fluid, seamless interaction for users to enjoy.<\/li>\n<\/ul>\n<\/ul>\n<p>In this three-part series, we&#8217;ll introduce and deep dive into Media3\u2019s powerful utilities for (pre)loading components.<\/p>\n<ul>\n<ul>\n<li align=\"justify\">In Part 1, we&#8217;ll cover the foundations: understanding the different preloading strategies available in Media3, enabling PreloadConfiguration and setting up the DefaultPreloadManager, enabling your app to preload items. By the end of this blog, you should be able to preload and play media items with your configured ranking and duration. <\/li>\n<li align=\"justify\">In Part 2, we&#8217;ll get into more advanced topics of DefaultPreloadManager: using listeners for analytics, exploring production-ready best practices like the sliding window pattern and custom shared  components of DefaultPreloadManager and ExoPlayer.<\/li>\n<li align=\"justify\">In Part 3, we&#8217;ll dive deep into disk caching with DefaultPreloadManager.<\/li>\n<\/ul>\n<\/ul>\n<h2><span style=\"font-size: x-large;\">Preloading to the rescue! \ud83e\uddb8\u200d\u2640\ufe0f<\/span><\/h2>\n<p align=\"justify\">The core idea behind preloading is simple: load media content before you need it. By the time a user swipes to the next video, the first segments of the video are already downloaded and available, ready for immediate playback.<\/p>\n<p align=\"justify\">Think of it like a restaurant. A busy kitchen doesn&#8217;t wait for an order to start chopping onions. \ud83e\uddc5 They do their prep work in advance. Preloading is the prep work for your video player.<\/p>\n<p align=\"justify\">When enabled, preloading can help minimize join latency when a user skips to the next item before the playback buffer reaches the next item. The first period of the next window is prepared and video, audio and text samples are buffered. The preloaded period is later queued into the player with buffered samples immediately available and ready to be fed to the codec for rendering.<\/p>\n<p align=\"justify\">In Media3 there are two primary APIs for preloading, each suited for different use cases. Choosing the right API is the first step.<\/p>\n<h3><span style=\"font-size: large;\">1. Preloading playlist items with PreloadConfiguration<\/span><\/h3>\n<p align=\"justify\">This is the simple approach, useful for linear, sequential media like playlists where the playback order is predictable (like a series of episodes). You give the player the full list of media items using ExoPlayer&#8217;s <a href=\"https:\/\/developer.android.com\/media\/media3\/exoplayer\/playlists\" target=\"_blank\" rel=\"noopener\">playlist<\/a> APIs and set the <a href=\"https:\/\/developers.google.com\/admob\/android\/reference\/com\/google\/android\/gms\/ads\/preload\/PreloadConfiguration\" target=\"_blank\" rel=\"noopener\">PreloadConfiguration<\/a> for the player,  then it automatically preloads the next items in the sequence as configured. This API attempts to optimize the join latency when a user skips to the next item before the playback buffer already overlaps into the next item.<\/p>\n<p align=\"justify\">Preloading is only started when no media is being loaded for the ongoing playback, which prevents it from competing for bandwidth with the primary playback.<\/p>\n<p align=\"justify\">If you\u2019re still not sure whether you need preloading, this API is a great low-lift option to try it out!<\/p>\n<p><!--Kotlin--><\/p>\n<div style=\"background: #f8f8f8; overflow:auto;width:auto;border:0;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span\/>player.<span style=\"color: #687822\">preloadConfiguration<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">=<\/span>\n<span style=\"color: #BBB\">    <\/span>PreloadConfiguration(<span style=\"color: #3D7B7B; font-style: italic\">\/* targetPreloadDurationUs= *\/<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">5<\/span>_000_000L)\n<\/pre>\n<\/div>\n<p align=\"justify\">With the <a href=\"https:\/\/developer.android.com\/reference\/kotlin\/androidx\/media3\/exoplayer\/ExoPlayer.PreloadConfiguration\" target=\"_blank\" rel=\"noopener\">PreloadConfiguration<\/a> above, the player tries to preload five seconds of media for the next item in the playlist.<\/p>\n<p>Once opted-in, playlist preloading can be turned off again by using <span style=\"color: #0d904f ;font-family: courier;\">PreloadConfiguration.DEFAULT<\/span> to disable playlist preloading:<\/p>\n<p><!--Kotlin--><\/p>\n<div style=\"background: #f8f8f8; overflow:auto;width:auto;border:0;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span\/>player.<span style=\"color: #687822\">preloadConfiguration<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">=<\/span><span style=\"color: #BBB\"> <\/span>PreloadConfiguration.<span style=\"color: #687822\">DEFAULT<\/span>\n<\/pre>\n<\/div>\n<h3><span style=\"font-size: large;\">2. Preloading dynamic lists with PreloadManager<\/span><\/h3>\n<p align=\"justify\">For dynamic UIs like vertical feeds or carousels, where the &#8220;next&#8221; item is determined by user interaction, the PreloadManager API is appropriate. This is a new powerful, standalone  component within the Media3 ExoPlayer library specifically designed to proactively preload. It manages a collection of potential MediaSources, prioritizing them based on proximity to the user&#8217;s current position and offers <b><u>granular<\/u><\/b> control over what to preload, suitable for complex scenarios like dynamic feeds of short form videos.<\/p>\n<h4><span style=\"font-size: medium;\">Setting Up Your PreloadManager<\/span><\/h4>\n<p align=\"justify\">The <a href=\"https:\/\/developer.android.com\/reference\/androidx\/media3\/exoplayer\/source\/preload\/DefaultPreloadManager\" target=\"_blank\" rel=\"noopener\">DefaultPreloadManager<\/a> is the canonical implementation for PreloadManager.<\/p>\n<p align=\"justify\">The builder of <span style=\"color: #0d904f ;font-family: courier;\">DefaultPreloadManager<\/span> can build both the DefaultPreloadManager and any <a href=\"https:\/\/developer.android.com\/media\/media3\/exoplayer\" target=\"_blank\" rel=\"noopener\">ExoPlayer<\/a> instances that will play its preloaded content. To create a DefaultPreloadManager, you will need to pass a TargetPreloadStatusControl, which the preload manager can query to find out how much to load for an item. We will explain and define an example of TargetPreloadStatusControl in the section below.<\/p>\n<p><!--Kotlin--><\/p>\n<div style=\"background: #f8f8f8; overflow:auto;width:auto;border:0;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span\/><span style=\"color: #008000; font-weight: bold\">val<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #19177C\">preloadManagerBuilder<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">=<\/span>\nDefaultPreloadManager.<span style=\"color: #687822\">Builder<\/span>(context,<span style=\"color: #BBB\"> <\/span>targetPreloadStatusControl)\n<span style=\"color: #008000; font-weight: bold\">val<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #19177C\">preloadManager<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">=<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #008000; font-weight: bold\">val<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #19177C\">preloadManagerBuilder<\/span>.<span style=\"color: #687822\">build<\/span>()\n\n<span style=\"color: #3D7B7B; font-style: italic\">\/\/ Build ExoPlayer with DefaultPreloadManager.Builder<\/span>\n<span style=\"color: #008000; font-weight: bold\">val<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #19177C\">player<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">=<\/span><span style=\"color: #BBB\"> <\/span>preloadManagerBuilder.<span style=\"color: #687822\">buildExoPlayer<\/span>()\n<\/pre>\n<\/div>\n<p align=\"justify\">Using the same <a href=\"https:\/\/developer.android.com\/reference\/androidx\/media3\/exoplayer\/source\/preload\/DefaultPreloadManager.Builder#build()\" target=\"_blank\" rel=\"noopener\">builder<\/a> for both the ExoPlayer and DefaultPreloadManager is necessary, which ensures that the components under the hood of them are correctly shared.<\/p>\n<p align=\"justify\">And that&#8217;s it! You now have a manager ready to receive instructions.<\/p>\n<h4><span style=\"font-size: medium;\">Configuring Duration and Ranking with <a href=\"https:\/\/developer.android.com\/reference\/androidx\/media3\/exoplayer\/source\/preload\/TargetPreloadStatusControl\" target=\"_blank\" rel=\"noopener\">TargetPreloadStatusControl<\/a><\/span><\/h4>\n<p align=\"justify\">What if you want to preload, say, 10 seconds of video ? You can provide the position of your media items in the carousel, and the DefaultPreloadManager prioritizes loading the items based on how close it is to the item the user is currently playing.<\/p>\n<p align=\"justify\">If you want to control how much duration of the item to preload, you can tell that with DefaultPreloadManager.PreloadStatus you return.<\/p>\n<p>For example,<\/p>\n<ul>\n<ul>\n<li align=\"justify\">Item \u2018A\u2019 is the highest priority, load 5 seconds of video.<\/li>\n<li align=\"justify\">Item \u2018B\u2019 is medium priority but when you get to it, load 3 seconds of video.<\/li>\n<li align=\"justify\">Item \u2018C\u2019 is less priority, load only tracks.<\/li>\n<li align=\"justify\">Item \u2018D\u2019 is even less of a priority, just prepare.<\/li>\n<li align=\"justify\">Any other items are far away, Don\u2019t preload anything.<\/li>\n<\/ul>\n<\/ul>\n<p align=\"justify\">This granular control can help you optimize your resource utilization which is recommended for a seamless playback.<\/p>\n<p><!--Kotlin--><\/p>\n<div style=\"background: #f8f8f8; overflow:auto;width:auto;border:0;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span\/><span style=\"color: #008000; font-weight: bold\">import<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #00F; font-weight: bold\">androidx.media3.exoplayer.DefaultPreloadManager.PreloadStatus<\/span>\n\n\n<span style=\"color: #008000; font-weight: bold\">class<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #00F; font-weight: bold\">MyTargetPreloadStatusControl<\/span>(\n<span style=\"color: #BBB\">    <\/span>currentPlayingIndex:<span style=\"color: #BBB\"> <\/span><span style=\"color: #B00040\">Int<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">=<\/span><span style=\"color: #BBB\"> <\/span>C.<span style=\"color: #687822\">INDEX_UNSET<\/span>\n)<span style=\"color: #BBB\"> <\/span>:<span style=\"color: #BBB\"> <\/span>TargetPreloadStatusControl<span style=\"color: #666\">&lt;<\/span><span style=\"color: #B00040\">Int<\/span>,PreloadStatus<span style=\"color: #666\">&gt;<\/span><span style=\"color: #BBB\"> <\/span>{\n\n\n<span style=\"color: #BBB\">    <\/span><span style=\"color: #3D7B7B; font-style: italic\">\/\/ The app is responsible for updating this based on UI state<\/span>\n<span style=\"color: #BBB\">    <\/span><span style=\"color: #008000; font-weight: bold\">override<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #008000; font-weight: bold\">fun<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #00F\">getTargetPreloadStatus<\/span>(index:<span style=\"color: #BBB\"> <\/span><span style=\"color: #B00040\">Int<\/span>):<span style=\"color: #BBB\"> <\/span>PreloadStatus? {\n\n<span style=\"color: #BBB\">        <\/span><span style=\"color: #008000; font-weight: bold\">val<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #19177C\">distance<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">=<\/span><span style=\"color: #BBB\"> <\/span>index<span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">-<\/span><span style=\"color: #BBB\"> <\/span>currentPlayingIndex\n\n<span style=\"color: #BBB\">        <\/span><span style=\"color: #3D7B7B; font-style: italic\">\/\/ Adjacent items (Next): preload 5 seconds<\/span>\n<span style=\"color: #BBB\">        <\/span><span style=\"color: #008000; font-weight: bold\">if<\/span><span style=\"color: #BBB\"> <\/span>(distance<span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">==<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">1<\/span>)<span style=\"color: #BBB\"> <\/span>{<span style=\"color: #BBB\"> <\/span>\n<span style=\"color: #BBB\">        <\/span><span style=\"color: #3D7B7B; font-style: italic\">\/\/ Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED and suggest loading \/\/ 5000ms from the default start position<\/span>\n<span style=\"color: #BBB\">                    <\/span><span style=\"color: #008000; font-weight: bold\">return<\/span><span style=\"color: #BBB\"> <\/span>PreloadStatus.<span style=\"color: #687822\">specifiedRangeLoaded<\/span>(<span style=\"color: #666\">5000L<\/span>)\n<span style=\"color: #BBB\">                <\/span>}<span style=\"color: #BBB\"> <\/span>\n\n<span style=\"color: #BBB\">        <\/span><span style=\"color: #3D7B7B; font-style: italic\">\/\/ Adjacent items (Previous): preload 3 seconds<\/span>\n<span style=\"color: #BBB\">        <\/span><span style=\"color: #008000; font-weight: bold\">else<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #008000; font-weight: bold\">if<\/span><span style=\"color: #BBB\"> <\/span>(distance<span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">==<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">-1<\/span>)<span style=\"color: #BBB\"> <\/span>{<span style=\"color: #BBB\"> <\/span>\n<span style=\"color: #BBB\">        <\/span><span style=\"color: #3D7B7B; font-style: italic\">\/\/ Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED \/\/and suggest loading 3000ms from the default start position<\/span>\n<span style=\"color: #BBB\">                    <\/span><span style=\"color: #008000; font-weight: bold\">return<\/span><span style=\"color: #BBB\"> <\/span>PreloadStatus.<span style=\"color: #687822\">specifiedRangeLoaded<\/span>(<span style=\"color: #666\">3000L<\/span>)\n<span style=\"color: #BBB\">                <\/span>}<span style=\"color: #BBB\"> <\/span>\n\n<span style=\"color: #BBB\">        <\/span><span style=\"color: #3D7B7B; font-style: italic\">\/\/ Items two positions away: just select tracks<\/span>\n<span style=\"color: #BBB\">        <\/span><span style=\"color: #008000; font-weight: bold\">else<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #008000; font-weight: bold\">if<\/span><span style=\"color: #BBB\"> <\/span>(distance)<span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">==<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">2<\/span>)<span style=\"color: #BBB\"> <\/span>{\n<span style=\"color: #BBB\">        <\/span><span style=\"color: #3D7B7B; font-style: italic\">\/\/ Return a PreloadStatus that is labelled by STAGE_TRACKS_SELECTED<\/span>\n<span style=\"color: #BBB\">                    <\/span><span style=\"color: #008000; font-weight: bold\">return<\/span><span style=\"color: #BBB\"> <\/span>PreloadStatus.<span style=\"color: #687822\">TRACKS_SELECTED<\/span>\n<span style=\"color: #BBB\">                <\/span>}<span style=\"color: #BBB\"> <\/span>\n\n<span style=\"color: #BBB\">        <\/span><span style=\"color: #3D7B7B; font-style: italic\">\/\/ Items four positions away: just select prepare<\/span>\n<span style=\"color: #BBB\">        <\/span><span style=\"color: #008000; font-weight: bold\">else<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #008000; font-weight: bold\">if<\/span><span style=\"color: #BBB\"> <\/span>(abs(distance)<span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">&lt;=<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">4<\/span>)<span style=\"color: #BBB\"> <\/span>{\n<span style=\"color: #BBB\">        <\/span><span style=\"color: #3D7B7B; font-style: italic\">\/\/ Return a PreloadStatus that is labelled by STAGE_SOURCE_PREPARED<\/span>\n<span style=\"color: #BBB\">                    <\/span><span style=\"color: #008000; font-weight: bold\">return<\/span><span style=\"color: #BBB\"> <\/span>PreloadStatus.<span style=\"color: #687822\">SOURCE_PREPARED<\/span>\n<span style=\"color: #BBB\">                <\/span>}\n\n<span style=\"color: #BBB\">             <\/span><span style=\"color: #3D7B7B; font-style: italic\">\/\/ All other items are too far away<\/span>\n<span style=\"color: #BBB\">             <\/span><span style=\"color: #008000; font-weight: bold\">return<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #008000; font-weight: bold\">null<\/span>\n<span style=\"color: #BBB\">            <\/span>}\n}\n<\/pre>\n<\/div>\n<p align=\"justify\"><em>Tip: PreloadManager can keep both the previous and next items preloaded, whereas the PreloadConfiguration will only look ahead to the next items.<\/em><\/p>\n<h4><span style=\"font-size: medium;\">Managing Preloading Items<\/span><\/h4>\n<p align=\"justify\">With your manager created, you can start telling it what to work on. As your user scrolls through a feed, you&#8217;ll identify the upcoming videos and add them to the manager. The interaction with the PreloadManager is a state-driven conversation between your UI and the preloading engine.<\/p>\n<p><b>1. Add Media Items<\/b><\/p>\n<p align=\"justify\">As you populate your feed, you must inform the <a href=\"https:\/\/developer.android.com\/reference\/androidx\/media3\/exoplayer\/source\/preload\/DefaultPreloadManager\" target=\"_blank\" rel=\"noopener\">manager<\/a> of the media it needs to track. If you are starting, you could add the entire list you want to preload. Subsequently you can keep adding a single item to the list as and when required. You have full control over what items are in the preloading list which means you also have to manage what is added and removed from the manager.<\/p>\n<p><!--Kotlin--><\/p>\n<div style=\"background: #f8f8f8; overflow:auto;width:auto;border:0;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span\/><span style=\"color: #008000; font-weight: bold\">val<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #19177C\">initialMediaItems<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">=<\/span><span style=\"color: #BBB\"> <\/span>pullMediaItemsFromService(<span style=\"color: #3D7B7B; font-style: italic\">\/* count= *\/<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">20<\/span>)\n<span style=\"color: #008000; font-weight: bold\">for<\/span><span style=\"color: #BBB\"> <\/span>(index<span style=\"color: #BBB\"> <\/span><span style=\"color: #008000; font-weight: bold\">in<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">0<\/span><span style=\"color: #BBB\"> <\/span>until<span style=\"color: #BBB\"> <\/span>initialMediaItems.<span style=\"color: #687822\">size<\/span>)<span style=\"color: #BBB\"> <\/span>{\n<span style=\"color: #BBB\">    <\/span>preloadManager.<span style=\"color: #687822\">add<\/span>(\n<span style=\"color: #BBB\">        <\/span>initialMediaItems.<span style=\"color: #687822\">get<\/span>(index),index)\n<span style=\"color: #BBB\">    <\/span>)\n}\n<\/pre>\n<\/div>\n<p align=\"justify\">The manager will now start fetching data for this <span style=\"color: #0d904f ;font-family: courier;\">MediaItem<\/span> in the background.<\/p>\n<p align=\"justify\">After adding, tell the manager to re-evaluate its new list (hinting that something has changed like adding\/ removing an item, or the user switches to play a new item.)<\/p>\n<p><!--Kotlin--><\/p>\n<div style=\"background: #f8f8f8; overflow:auto;width:auto;border:0;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span\/>preloadManager.<span style=\"color: #687822\">invalidate<\/span>()\n<\/pre>\n<\/div>\n<p><b>2. Retrieve and Play an Item<\/b><\/p>\n<p align=\"justify\">Here comes the main playback logic. When the user decides to play that video, you don&#8217;t need to create a new <span style=\"color: #0d904f ;font-family: courier;\">MediaSource<\/span>. Instead, you ask the <span style=\"color: #0d904f ;font-family: courier;\">PreloadManager<\/span> for the one it has already prepared. You can retrieve the MediaSource from the Preload Manager using the MediaItem.<\/p>\n<p align=\"justify\">If the retrieved item from the PreloadManager is null, that means the mediaItem is not preloaded yet or added to the PreloadMamager, so you choose to set the mediaItem directly.<\/p>\n<p><!--Kotlin--><\/p>\n<div style=\"background: #f8f8f8; overflow:auto;width:auto;border:0;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span\/><span style=\"color: #3D7B7B; font-style: italic\">\/\/ When a media item is about to displ\u200b\u200bay on the screen<\/span>\n<span style=\"color: #008000; font-weight: bold\">val<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #19177C\">mediaSource<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #666\">=<\/span><span style=\"color: #BBB\"> <\/span>preloadManager.<span style=\"color: #687822\">getMediaSource<\/span>(mediaItem)\n<span style=\"color: #008000; font-weight: bold\">if<\/span><span style=\"color: #BBB\"> <\/span>(mediaSource<span style=\"color: #666\">!=<\/span><span style=\"color: #BBB\"> <\/span><span style=\"color: #008000; font-weight: bold\">null<\/span>)<span style=\"color: #BBB\"> <\/span>{\n<span style=\"color: #BBB\">  <\/span>player.<span style=\"color: #687822\">setMediaSource<\/span>(mediaSource)\n}<span style=\"color: #BBB\"> <\/span><span style=\"color: #008000; font-weight: bold\">else<\/span><span style=\"color: #BBB\"> <\/span>{\n<span style=\"color: #BBB\">  <\/span><span style=\"color: #3D7B7B; font-style: italic\">\/\/ If mediaSource is null, that mediaItem hasn't been added yet.<\/span>\n<span style=\"color: #BBB\">  <\/span><span style=\"color: #3D7B7B; font-style: italic\">\/\/ So, send it directly to the player.<\/span>\n<span style=\"color: #BBB\">  <\/span>player.<span style=\"color: #687822\">setMediaItem<\/span>(mediaItem)\n}\nplayer.<span style=\"color: #687822\">prepare<\/span>()\n<span style=\"color: #3D7B7B; font-style: italic\">\/\/ When the media item is displaying at the center of the screen<\/span>\nplayer.<span style=\"color: #687822\">play<\/span>()\n<\/pre>\n<\/div>\n<p align=\"justify\">By preparing the MediaSource retrieved from the PreloadManager, you seamlessly transition from preloading to playback, using the data that&#8217;s already in memory. This is what makes the start time faster.<\/p>\n<p><b>3. Keep the current index in sync with the UI<\/b><\/p>\n<p align=\"justify\">Since our feed \/ list could be dynamic, it&#8217;s important to notify the PreloadManager of your current playing index so that it can always prioritize items nearest to your current index for preloading.<\/p>\n<p><!--Kotlin--><\/p>\n<div style=\"background: #f8f8f8; overflow:auto;width:auto;border:0;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span\/>preloadManager.<span style=\"color: #687822\">setCurrentPlayingIndex<\/span>(currentIndex)\n<span style=\"color: #3D7B7B; font-style: italic\">\/\/ Need to call invalidate() to update the priorities<\/span>\npreloadManager.<span style=\"color: #687822\">invalidate<\/span>()\n<\/pre>\n<\/div>\n<p><b>4. Remove an Item<\/b><\/p>\n<p align=\"justify\">To keep the manager efficient, you should remove items it no longer needs to track, such as items that are far away from the user&#8217;s current position.<\/p>\n<p><!--Kotlin--><\/p>\n<div style=\"background: #f8f8f8; overflow:auto;width:auto;border:0;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span\/><span style=\"color: #3D7B7B; font-style: italic\">\/\/ When an item is too far from the current playing index<\/span>\npreloadManager.<span style=\"color: #687822\">remove<\/span>(mediaItem)\n<\/pre>\n<\/div>\n<p align=\"justify\">If you need to clear all items at once, you can call preloadManager.reset().<\/p>\n<p><b>5. Release the Manager<\/b><\/p>\n<p align=\"justify\">When you no longer need the PreloadManager (e.g., when your UI is destroyed), you must release it to free up its resources. A good place to do this is where you\u2019re already releasing your Player\u2019s resources. It\u2019s recommended to release the manager before the player as the player can continue to play if you don&#8217;t need any more preloading.<\/p>\n<p><!--Kotlin--><\/p>\n<div style=\"background: #f8f8f8; overflow:auto;width:auto;border:0;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span\/><span style=\"color: #3D7B7B; font-style: italic\">\/\/ In your Activity's onDestroy() or Composable's onDispose<\/span>\npreloadManager.<span style=\"color: #687822\">release<\/span>()\n<\/pre>\n<\/div>\n<h3><span style=\"font-size: large;\">Demo time<\/span><\/h3>\n<h4><span style=\"font-size: medium;\">Check it live in action \ud83d\udc4d<\/span><\/h4>\n<p align=\"justify\">In the demo below , we see the impact of PreloadManager on the right side which has faster load times, whereas the left side shows the existing experience. You can also view the code <a href=\"https:\/\/github.com\/android\/socialite\/tree\/ui_polishes_short_videos\" target=\"_blank\" rel=\"noopener\">sample<\/a> for the demo. (Bonus: It also displays startup latency for every video)<\/p>\n<p><image><\/p>\n<div style=\"text-align: center;\"><img decoding=\"async\" alt=\"Jetpack Media3 API for fast loading of short videos [PreloadManager]\" border=\"0\" id=\"imgCaption\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEgPRidTRe3s-2TIek6_YlfUsFwxRAaH-6rynAMXLX7UwVM9b-PhCAfOqAWwrTIBj6pSfntZizlYLU6nhmkNqbwwvBLGkWRjsOKNb-c56Jr8gutxBkSZidmOP1T420tBU5knaVvuAygMKHnDV8epXMc2TuIZN2klfnIKulNQUncwfz4fuuIlbLQ3yxhrhrU\/s1600\/Demo-PreloadManager%202.gif\" width=\"100%\"\/><\/div>\n<p><\/image><\/p>\n<h2><span style=\"font-size: x-large;\">What&#8217;s Next?<\/span><\/h2>\n<p align=\"justify\">And that&#8217;s a wrap for Part 1! You now have the tools to build a dynamic preloading system. You can either use <span style=\"color: #0d904f ;font-family: courier;\">PreloadConfiguration<\/span> to preload the next item of a playlist in ExoPlayer or set up a <span style=\"color: #0d904f ;font-family: courier;\">DefaultPreloadManager<\/span>, add and remove items on the fly, configure the target preload status, and correctly retrieve the preloaded content for playback.<\/p>\n<p align=\"justify\">In <b>Part 2<\/b>, we&#8217;ll go deeper on the <span style=\"color: #0d904f ;font-family: courier;\">DefaultPreloadManager<\/span>. We&#8217;ll explore how to listen for preloading events, discuss best practices like using a sliding window to avoid memory issues, and peek under the hood at custom shared components of ExoPlayer and DefaultPreloadManager.<\/p>\n<p align=\"justify\">Do you have any feedback to <a href=\"https:\/\/github.com\/androidx\/media\/issues\" target=\"_blank\" rel=\"noopener\">share<\/a>? We are eager to hear from you.<\/p>\n<p align=\"justify\">Stay tuned, and go make your app faster! \ud83d\ude80<\/p>\n<\/div>\n<p>[ad_2]<br \/>\n<br \/><a href=\"http:\/\/android-developers.googleblog.com\/2025\/09\/introducing-preloading-with-media3.html\">Source link <\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>[ad_1] Posted by Mayuri Khinvasara Khabya &#8211; Developer Relations Engineer (LinkedIn and X) In today&#8217;s media-centric apps, delivering a smooth, uninterrupted playback experience is key<\/p>\n","protected":false},"author":1,"featured_media":347805,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[146],"tags":[],"_links":{"self":[{"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/posts\/347804"}],"collection":[{"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/comments?post=347804"}],"version-history":[{"count":0,"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/posts\/347804\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/media\/347805"}],"wp:attachment":[{"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/media?parent=347804"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/categories?post=347804"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/tags?post=347804"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}