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 d'offrir une expérience de lecture fluide et ininterrompue pour garantir 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.
La principale difficulté 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 cet article de 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, où 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 de 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
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, l'API PreloadManager est appropriée. 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 précis 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 afin de s'assurer 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 trois 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 se 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 indiquer au gestionnaire les 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 le MediaSource récupéré à 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 accélère le temps de démarrage.
3. Synchroniser l'index actuel avec l'UI
Étant donné que notre flux / notre 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 les éléments qui sont loin 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, nous voyons l'impact de PreloadManager sur le côté droit, qui présente des temps de chargement plus rapides, tandis que le côté gauche montre l'expérience existante. Vous pouvez également consulter l'exemple de code de 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 en détail 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 rendez votre application plus rapide ! 🚀
-
Actualités des produitsBienvenue 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 produitsChez Google Play, nous nous engageons à offrir la meilleure expérience possible aux utilisateurs, tout en veillant à ce que les développeurs disposent des outils et de la flexibilité nécessaires pour réussir.
Paul Feng • Temps de lecture : 3 min -
Actualités des produitsL'année dernière, nous avons introduit la validation des développeurs Android pour renforcer la sécurité de l'écosystème et empêcher les personnes malintentionnées de se cacher derrière l'anonymat pour publier des applications dangereuses.
Matthew Forsythe • Temps de lecture : 2 min
Recevez chaque semaine les dernières informations sur le développement Android directement dans votre boîte de réception.