Actualités des produits
Améliorer la lecture de contenus multimédias : présentation du préchargement avec Media3 – Partie 1
Temps de lecture : 8 min
Dans les applications multimédias d'aujourd'hui, il est essentiel de proposer une expérience de lecture fluide et ininterrompue pour offrir une expérience utilisateur agréable. Les utilisateurs s'attendent à ce que leurs vidéos démarrent instantanément et soient lues de manière fluide, sans pause.
Le principal défi est la latence. Traditionnellement, un lecteur vidéo ne commence son travail (connexion, téléchargement, analyse, mise en mémoire tampon) qu'une fois que l'utilisateur a choisi un élément à lire. Cette approche réactive est lente dans le contexte actuel des vidéos courtes. La solution consiste à être proactif. Nous devons anticiper ce que l'utilisateur va regarder ensuite et préparer le contenu à l'avance. C'est l'essence du préchargement.
Voici les principaux avantages du préchargement :
- 🚀 Démarrage de la lecture plus rapide : les vidéos sont déjà prêtes, ce qui permet des transitions plus rapides entre les éléments et un démarrage plus immédiat.
- 📉 Mise en mémoire tampon réduite : en chargeant les données de manière proactive, la lecture est beaucoup moins susceptible de s'interrompre, par exemple en raison de problèmes de réseau.
- ✨ Expérience utilisateur plus fluide : la combinaison de démarrages plus rapides et de moins de mise en mémoire tampon crée une interaction plus fluide et transparente pour les utilisateurs.
Dans cette série en trois parties, nous allons vous présenter les puissants utilitaires de Media3 pour le préchargement de composants et les examiner en détail.
- Dans la partie 1, nous aborderons les bases : comprendre les différentes stratégies de préchargement disponibles dans Media3, activer PreloadConfiguration et configurer DefaultPreloadManager, ce qui permettra à votre application de précharger des éléments. À la fin de ce blog, vous devriez être en mesure de précharger et de lire des éléments multimédias avec le classement et la durée que vous avez configurés.
- Dans la partie 2, nous aborderons des sujets plus avancés concernant DefaultPreloadManager : l'utilisation d'écouteurs pour l'analyse, l'exploration des bonnes pratiques prêtes pour la production telles que le modèle de fenêtre coulissante et les composants partagés personnalisés de DefaultPreloadManager et ExoPlayer.
- Dans la partie 3, nous allons nous pencher en détail sur la mise en cache sur disque avec DefaultPreloadManager.
Le préchargement à la rescousse ! 🦸♀️
L'idée de base du préchargement est simple : charger le contenu multimédia avant d'en avoir besoin. Lorsque l'utilisateur balaie l'écran pour passer à la vidéo suivante, les premiers segments de la vidéo sont déjà téléchargés et disponibles pour une lecture immédiate.
Imaginez un restaurant. Dans une cuisine animée, on ne commence pas à émincer les oignons une fois la commande passée. 🧅 Ils préparent leur travail à l'avance. Le préchargement est la préparation de votre lecteur vidéo.
Lorsqu'il est activé, le préchargement peut aider à réduire la latence de connexion lorsqu'un utilisateur passe à l'élément suivant avant que le tampon de lecture n'atteigne cet élément. La première période de la fenêtre suivante est préparée, et des exemples de vidéo, d'audio et de texte sont mis en mémoire tampon. La période préchargée est ensuite mise en file d'attente dans le lecteur, avec des échantillons mis en mémoire tampon immédiatement disponibles et prêts à être transmis au codec pour le rendu.
Dans Media3, il existe deux API principales pour le préchargement, chacune étant adaptée à des cas d'utilisation différents. La première étape consiste à choisir la bonne API.
1. Précharger des éléments de playlist avec PreloadConfiguration
Il s'agit de l'approche simple, utile pour les contenus multimédias linéaires et séquentiels tels que les playlists dont l'ordre de lecture est prévisible (comme une série d'épisodes). Vous fournissez au lecteur la liste complète des éléments multimédias à l'aide des API playlist d'ExoPlayer et définissez la PreloadConfiguration pour le lecteur. Ensuite, il précharge automatiquement les éléments suivants de la séquence selon la configuration. Cette API tente d'optimiser la latence de participation lorsqu'un utilisateur passe à l'élément suivant avant que le tampon de lecture ne se chevauche déjà avec l'élément suivant.
Le préchargement ne démarre que lorsqu'aucun contenu multimédia n'est en cours de chargement pour la lecture en cours, ce qui l'empêche de concurrencer la lecture principale pour la bande passante.
Si vous n'êtes toujours pas sûr d'avoir besoin du préchargement, cette API est une excellente option simple à essayer.
player.preloadConfiguration =
PreloadConfiguration(/* targetPreloadDurationUs= */ 5_000_000L)Avec la PreloadConfiguration ci-dessus, le lecteur tente de précharger cinq secondes de contenu multimédia pour l'élément suivant de la playlist.
Une fois l'option activée, vous pouvez la désactiver à l'aide de PreloadConfiguration.DEFAULT :
player.preloadConfiguration = PreloadConfiguration.DEFAULT
2. Précharger des listes dynamiques avec PreloadManager
L'API PreloadManager est appropriée pour les UI dynamiques telles que les flux verticaux ou les carrousels, où l'élément "suivant" est déterminé par l'interaction de l'utilisateur. Il s'agit d'un nouveau composant autonome et puissant de la bibliothèque Media3 ExoPlayer, spécialement conçu pour le préchargement proactif. Il gère une collection de MediaSources potentielles, en les classant par ordre de priorité en fonction de leur proximité avec la position actuelle de l'utilisateur, et offre un contrôle granulaire sur les éléments à précharger, ce qui convient aux scénarios complexes tels que les flux dynamiques de vidéos courtes.
Configurer votre PreloadManager
DefaultPreloadManager est l'implémentation canonique de PreloadManager.
Le compilateur de DefaultPreloadManager peut compiler à la fois le DefaultPreloadManager et toutes les instances ExoPlayer qui liront son contenu préchargé. Pour créer un DefaultPreloadManager, vous devez transmettre un TargetPreloadStatusControl, que le gestionnaire de préchargement peut interroger pour savoir quelle quantité charger pour un élément. Nous allons expliquer et définir un exemple de TargetPreloadStatusControl dans la section ci-dessous.
val preloadManagerBuilder = DefaultPreloadManager.Builder(context, targetPreloadStatusControl) val preloadManager = val preloadManagerBuilder.build() // Build ExoPlayer with DefaultPreloadManager.Builder val player = preloadManagerBuilder.buildExoPlayer()
Il est nécessaire d'utiliser le même compilateur pour ExoPlayer et DefaultPreloadManager, ce qui garantit que les composants sous-jacents sont correctement partagés.
Et voilà ! Vous disposez maintenant d'un gestionnaire prêt à recevoir des instructions.
Configurer la durée et le classement avec TargetPreloadStatusControl
Que faire si vous souhaitez précharger, par exemple, 10 secondes de vidéo ? Vous pouvez indiquer la position de vos éléments multimédias dans le carrousel. DefaultPreloadManager priorise le chargement des éléments en fonction de leur proximité avec l'élément que l'utilisateur est en train de lire.
Si vous souhaitez contrôler la durée de l'élément à précharger, vous pouvez l'indiquer avec DefaultPreloadManager.PreloadStatus.
Par exemple,
- L'élément A est la priorité la plus élevée. Chargez cinq secondes de vidéo.
- L'élément B est de priorité moyenne, mais lorsque vous y arrivez, chargez 3 secondes de vidéo.
- L'élément C est moins prioritaire. Seuls les suivis de chargement sont chargés.
- L'élément D est encore moins prioritaire. Il suffit de s'y préparer.
- Tous les autres éléments sont éloignés. Ne préchargez rien.
Ce contrôle précis peut vous aider à optimiser l'utilisation de vos ressources, ce qui est recommandé pour une lecture fluide.
import androidx.media3.exoplayer.DefaultPreloadManager.PreloadStatus
class MyTargetPreloadStatusControl(
currentPlayingIndex: Int = C.INDEX_UNSET
) : TargetPreloadStatusControl<Int,PreloadStatus> {
// The app is responsible for updating this based on UI state
override fun getTargetPreloadStatus(index: Int): PreloadStatus? {
val distance = index - currentPlayingIndex
// Adjacent items (Next): preload 5 seconds
if (distance == 1) {
// Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED and suggest loading // 5000ms from the default start position
return PreloadStatus.specifiedRangeLoaded(5000L)
}
// Adjacent items (Previous): preload 3 seconds
else if (distance == -1) {
// Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED //and suggest loading 3000ms from the default start position
return PreloadStatus.specifiedRangeLoaded(3000L)
}
// Items two positions away: just select tracks
else if (distance) == 2) {
// Return a PreloadStatus that is labelled by STAGE_TRACKS_SELECTED
return PreloadStatus.TRACKS_SELECTED
}
// Items four positions away: just select prepare
else if (abs(distance) <= 4) {
// Return a PreloadStatus that is labelled by STAGE_SOURCE_PREPARED
return PreloadStatus.SOURCE_PREPARED
}
// All other items are too far away
return null
}
}Remarque : PreloadManager peut conserver les éléments précédents et suivants préchargés, tandis que PreloadConfiguration ne s'intéresse qu'aux éléments suivants.
Gérer les éléments de préchargement
Maintenant que vous avez créé votre gestionnaire, vous pouvez commencer à lui dire sur quoi travailler. Lorsque l'utilisateur fait défiler un flux, vous identifiez les vidéos à venir et les ajoutez au gestionnaire. L'interaction avec PreloadManager est une conversation axée sur l'état entre votre UI et le moteur de préchargement.
1. Ajouter des éléments multimédias
Lorsque vous remplissez votre flux, vous devez informer le gestionnaire des médias qu'il doit suivre. Si vous débutez, vous pouvez ajouter toute la liste que vous souhaitez précharger. Vous pouvez ensuite continuer à ajouter un seul élément à la liste selon vos besoins. Vous contrôlez entièrement les éléments de la liste de préchargement. Vous devez donc également gérer ce qui est ajouté et supprimé du gestionnaire.
val initialMediaItems = pullMediaItemsFromService(/* count= */ 20)
for (index in 0 until initialMediaItems.size) {
preloadManager.add(
initialMediaItems.get(index),index)
)
}Le compte administrateur va maintenant commencer à récupérer les données de ce MediaItem en arrière-plan.
Après l'ajout, demandez au gestionnaire de réévaluer sa nouvelle liste (en indiquant qu'un élément a été ajouté ou supprimé, ou que l'utilisateur est passé à un nouvel élément).
preloadManager.invalidate()
2. Récupérer et lire un élément
Voici la logique de lecture principale. Lorsque l'utilisateur décide de lire cette vidéo, vous n'avez pas besoin de créer un nouvel MediaSource. Au lieu de cela, vous demandez à PreloadManager celui qu'il a déjà préparé. Vous pouvez récupérer MediaSource à partir du gestionnaire de préchargement à l'aide de MediaItem.
Si l'élément récupéré à partir de PreloadManager est nul, cela signifie que mediaItem n'est pas encore préchargé ni ajouté à PreloadManager. Vous pouvez donc choisir de définir mediaItem directement.
// When a media item is about to display on the screen
val mediaSource = preloadManager.getMediaSource(mediaItem)
if (mediaSource!= null) {
player.setMediaSource(mediaSource)
} else {
// If mediaSource is null, that mediaItem hasn't been added yet.
// So, send it directly to the player.
player.setMediaItem(mediaItem)
}
player.prepare()
// When the media item is displaying at the center of the screen
player.play()En préparant la MediaSource récupérée à partir du PreloadManager, vous passez en douceur du préchargement à la lecture, en utilisant les données déjà en mémoire. C'est ce qui permet d'accélérer le démarrage.
3. Synchroniser l'index actuel avec l'UI
Étant donné que notre flux / liste peut être dynamique, il est important d'informer PreloadManager de votre index de lecture actuel afin qu'il puisse toujours donner la priorité aux éléments les plus proches de votre index actuel pour le préchargement.
preloadManager.setCurrentPlayingIndex(currentIndex) // Need to call invalidate() to update the priorities preloadManager.invalidate()
4. Supprimer un élément
Pour que le gestionnaire reste efficace, vous devez supprimer les éléments qu'il n'a plus besoin de suivre, comme ceux qui sont éloignés de la position actuelle de l'utilisateur.
// When an item is too far from the current playing index preloadManager.remove(mediaItem)
Si vous devez effacer tous les éléments à la fois, vous pouvez appeler preloadManager.reset().
5. Libérer le gestionnaire
Lorsque vous n'avez plus besoin du PreloadManager (par exemple, lorsque votre UI est détruite), vous devez le libérer pour libérer ses ressources. Il est recommandé d'effectuer cette opération là où vous libérez déjà les ressources de votre lecteur. Il est recommandé de libérer le gestionnaire avant le lecteur, car le lecteur peut continuer à lire si vous n'avez plus besoin de préchargement.
// In your Activity's onDestroy() or Composable's onDispose preloadManager.release()
Démonstration
Découvrez-le en action 👍
Dans la démo ci-dessous, l'impact de PreloadManager est visible sur la droite, où les temps de chargement sont plus rapides, tandis que la gauche montre l'expérience existante. Vous pouvez également consulter l'exemple de code pour la démo. (Bonus : la latence de démarrage de chaque vidéo est également affichée.)
Et maintenant ?
C'est tout pour la partie 1 ! Vous disposez désormais des outils nécessaires pour créer un système de préchargement dynamique. Vous pouvez utiliser PreloadConfiguration pour précharger l'élément suivant d'une playlist dans ExoPlayer ou configurer un DefaultPreloadManager, ajouter et supprimer des éléments à la volée, configurer l'état de préchargement cible et récupérer correctement le contenu préchargé pour la lecture.
Dans la partie 2, nous approfondirons le DefaultPreloadManager. Nous allons explorer comment écouter les événements de préchargement, discuter des bonnes pratiques comme l'utilisation d'une fenêtre glissante pour éviter les problèmes de mémoire, et examiner les composants partagés personnalisés d'ExoPlayer et de DefaultPreloadManager.
Avez-vous des commentaires à partager ? Nous avons hâte de vous lire.
Restez à l'écoute et accélérez votre application ! 🚀
Lire la suite
-
Actualités des produits
Bienvenue dans le deuxième volet de notre série en trois parties sur le préchargement de contenu multimédia avec Media3. Cette série est conçue pour vous guider dans la création d'expériences multimédias très réactives et à faible latence dans vos applications Android.
Mayuri Khinvasara Khabya • Temps de lecture : 9 min
-
Actualités des produits
Lors de la conférence Google I/O 2026, nous avons annoncé qu'Android allait passer d'un système d'exploitation à un système intelligent. Nous avons également montré comment créer des expériences intelligentes de manière native avec le système et comment intégrer la puissance de l'IA de Google dans vos applications.
Jingyu Shi • 2 min de lecture
-
Actualités des produits
Nous sommes heureux d'annoncer que la prise en charge officielle d'Unreal Engine et de Godot est désormais disponible pour Android XR. Nous lançons également de nouveaux outils conçus pour booster votre productivité et activer de nouvelles fonctionnalités XR : Android XR Engine Hub et Android XR Interaction Framework.
Luke Hopkins, Ryan Bartley • Temps de lecture : 4 min
Restez informé
Recevez chaque semaine les dernières informations sur le développement Android directement dans votre boîte de réception.