أرسلت بواسطة Mayuri Khinvasara Khabya – مهندس علاقات المطورين (LinkedIn و X)

في التطبيقات التي تركز على وسائل الإعلام اليوم ، يعد تقديم تجربة تشغيل سلسة وغير متقطعة مفتاح تجربة المستخدم المبهجة. يتوقع المستخدمون أن تبدأ مقاطع الفيديو الخاصة بهم على الفور وتلعب بسلاسة دون توقف.
التحدي الأساسي هو الكمون. تقليديًا ، يبدأ مشغل الفيديو عمله فقط – التوصيل ، والتنزيل ، والتحليل ، والتخزين المؤقت – بعد أن اختار المستخدم عنصرًا للتشغيل. هذا النهج التفاعلي بطيء بالنسبة لسياق الفيديو القصير اليوم. الحل هو أن تكون استباقية. نحتاج إلى توقع ما سيشاهده المستخدم بعد ذلك ويجعل المحتوى جاهزًا في وقت مبكر. هذا هو جوهر التحميل المسبق.
تشمل الفوائد الرئيسية للتحميل المسبق:
- 🚀 بدء تشغيل أسرع: مقاطع الفيديو جاهزة بالفعل للذهاب ، مما يؤدي إلى انتقالات أسرع بين العناصر وبداية أكثر إلحاحًا.
- 📉 انخفاض التخزين المؤقت: من خلال تحميل البيانات بشكل استباقي ، من غير المرجح أن يتوقف التشغيل ، على سبيل المثال بسبب الفواق الشبكة.
- ✨ ناتجة عن تجربة مستخدم أكثر سلاسة: مزيج من البدايات الأسرع وأقل التخزين المؤقت يخلق تفاعلًا أكثر سائلًا وسلسًا للمستخدمين للاستمتاع به.
في هذه السلسلة المكونة من ثلاثة أجزاء ، سنقدم وعمق الغوص في الأدوات المساعدة القوية لـ Media3 لمكونات التحميل (قبل).
- في الجزء 1 ، سنقوم بتغطية الأسس: فهم استراتيجيات التحميل المسبقة المختلفة المتوفرة في Media3 ، مما يتيح تكوين مسبق وإعداد DefaultPreloadManager ، مما يتيح تطبيقك من العناصر المسبقة. بحلول نهاية هذه المدونة ، يجب أن تكون قادرًا على تحميل وتشغيل عناصر الوسائط مع تصنيفك ومدة تكوينه.
- في الجزء 2 ، سندخل في مواضيع أكثر تقدمًا من DefaultPreloadManager: استخدام المستمعين للتحليلات ، واستكشاف أفضل الممارسات جاهزة للإنتاج مثل نمط النافذة المنزلق والمكونات المشتركة المخصصة لـ DefaultPreloadManager و Exoplayer.
- في الجزء 3 ، سنغوص في أعماق التخزين المؤقت للقرص مع DefaultPreloadManager.
التحميل المسبق للإنقاذ! 🦸♀
الفكرة الأساسية وراء التحميل المسبق بسيط: تحميل محتوى الوسائط قبل أن تحتاج إليها. بحلول الوقت الذي ينقله المستخدم إلى الفيديو التالي ، يتم تنزيل الأجزاء الأولى من الفيديو بالفعل ومتاحة ، جاهزة للتشغيل الفوري.
فكر في الأمر مثل مطعم. لا ينتظر المطبخ المزدحم أن يبدأ الطلب في تقطيع البصل. 🧅 يقومون بعملهم الإعدادي مقدمًا. التحميل المسبق هو العمل الإعدادي لمشغل الفيديو الخاص بك.
عند التمكين ، يمكن أن تساعد التحميل المسبق للمساعدة في تقليل انضمام الانتقال عندما يتخطى المستخدم إلى العنصر التالي قبل أن يصل المخزن المؤقت للتشغيل إلى العنصر التالي. يتم إعداد الفترة الأولى من النافذة التالية ويتم تخزين عينات الفيديو والصوت والنص. يتم وضع الفترة المسبقة في قائمة الانتظار في وقت لاحق في اللاعب مع عينات مخزنة متوفرة على الفور وعلى استعداد لتغذيتها إلى برنامج الترميز لتقديمها.
في Media3 ، يوجد اثنين من واجهات برمجة التطبيقات الأولية للتحميل المسبق ، كل منهما مناسب لحالات الاستخدام المختلفة. اختيار واجهة برمجة التطبيقات المناسبة هو الخطوة الأولى.
1.
هذا هو النهج البسيط ، مفيد للوسائط الخطية المتسلسلة مثل قوائم التشغيل حيث يمكن التنبؤ بترتيب التشغيل (مثل سلسلة من الحلقات). يمكنك منح المشغل القائمة الكاملة لعناصر الوسائط باستخدام واجهات برمجة تطبيقات قائمة التشغيل الخاصة بـ Exoplayer وتعيين عملية تكوين المشغل المسبق ، ثم تقوم تلقائيًا بتحويل العناصر التالية في التسلسل كما تم تكوينه. تحاول واجهة برمجة التطبيقات هذه تحسين زمن انتقال الانضمام عندما يتخطى المستخدم إلى العنصر التالي قبل أن يتداخل المخزن المؤقت للتشغيل بالفعل في العنصر التالي.
يتم تشغيل التحميل المسبق فقط عندما لا يتم تحميل أي وسائط للتشغيل المستمر ، مما يمنعها من التنافس على النطاق الترددي مع التشغيل الأساسي.
إذا كنت لا تزال غير متأكد مما إذا كنت بحاجة إلى التحميل المسبق ، فإن واجهة برمجة التطبيقات هذه هي خيار كبير منخفض الارتفاع لتجربته!
player.preloadConfiguration = PreloadConfiguration(/* targetPreloadDurationUs= */ 5_000_000L)
مع التكوين المسبق أعلاه ، يحاول اللاعب التحميل المسبق لخمس ثوان من الوسائط للعنصر التالي في قائمة التشغيل.
بمجرد الاختيار ، يمكن إيقاف تشغيل التحميل المسبق لاستخدام قائمة التشغيل مرة أخرى باستخدام preloadConfiguration.default لتعطيل التحميل المسبق لقائمة التشغيل:
player.preloadConfiguration = PreloadConfiguration.DEFAULT
2. القوائم الديناميكية المسبقة مع preloadmanager
بالنسبة للاتصالات الديناميكية مثل الخلاصات الرأسية أو الكاروسيل ، حيث يتم تحديد العنصر “التالي” من خلال تفاعل المستخدم ، فإن واجهة برمجة تطبيقات PreloadManager مناسبة. هذا مكون جديد قوي ، مستقل في مكتبة Media3 Exoplayer مصممة خصيصًا للتحميل المسبق بشكل استباقي. يدير مجموعة من وسائل الإعلام المحتملة ، وتحديد أولوياتها بناءً على القرب من الموضع الحالي للمستخدم وتقديمها محبب التحكم في ما يجب التحميل المسبق ، مناسبة للسيناريوهات المعقدة مثل الخلاصات الديناميكية لمقاطع الفيديو القصيرة.
إعداد preloadmanager الخاص بك
The DefaultPreloadManager هو التنفيذ الكنسي لـ PreloadManager.
باني DefaultPreloadManager يمكن بناء كل من DefaultPreloadManager وأي حالات Exoplayer التي ستلعب محتواها المسبق. لإنشاء DefaultPreloadManager ، ستحتاج إلى تمرير TargetPreloadStatusControl ، والتي يمكن لمدير التحميل المسبق الاستعلام لمعرفة مقدار التحميل لعنصر. سنشرح ونحدد مثالًا على TargetPreloadStatusControl في القسم أدناه.
val preloadManagerBuilder = DefaultPreloadManager.Builder(context, targetPreloadStatusControl) val preloadManager = val preloadManagerBuilder.build() // Build ExoPlayer with DefaultPreloadManager.Builder val player = preloadManagerBuilder.buildExoPlayer()
من الضروري استخدام نفس المنشئ لكل من Exoplayer و DefaultPreloadManager ، مما يضمن مشاركة المكونات الموجودة تحت غطاء محرك السيارة بشكل صحيح.
وهذا كل شيء! لديك الآن مدير جاهز لتلقي التعليمات.
تكوين المدة والترتيب مع TargetPreloadStatusControl
ماذا لو كنت تريد التحميل المسبق ، على سبيل المثال ، 10 ثوان من الفيديو؟ يمكنك توفير موضع عناصر الوسائط الخاصة بك في carousel ، ويعطي DefaultPreloadManager أولوية تحميل العناصر بناءً على مدى قربه من العنصر الذي يلعبه المستخدم حاليًا.
إذا كنت ترغب في التحكم في مقدار مدة العنصر المسبق ، فيمكنك معرفة ذلك باستخدام DefaultPreloadManager.preloadstatus الذي تعود إليه.
على سبيل المثال،
- العنصر “A” هو أولوية أعلى ، تحميل 5 ثوان من الفيديو.
- العنصر “B” هو أولوية متوسطة ولكن عندما تحصل عليه ، قم بتحميل 3 ثوان من الفيديو.
- العنصر “C” أقل الأولوية ، وتحميل المسارات فقط.
- العنصر “D” أقل من أولوية ، فقط قم بالتحضير.
- أي عناصر أخرى بعيدة ، لا تُسبق أي شيء.
يمكن أن يساعدك هذا التحكم الحبيبي في تحسين استخدام الموارد الذي يوصى به لتشغيل سلس.
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 } }
نصيحة: يمكن لـ PreloadManager الحفاظ على كل من العناصر السابقة والجادمة مسبقًا ، في حين أن التكوين المسبق لن يتطلع فقط إلى العناصر التالية.
إدارة العناصر المسبقة
مع إنشاء مديرك ، يمكنك البدء في إخباره بما يجب العمل عليه. أثناء تمرير المستخدم الخاص بك من خلال التغذية ، ستحدد مقاطع الفيديو القادمة وإضافتها إلى المدير. التفاعل مع PreloadManager هو محادثة تعتمد على الدولة بين واجهة المستخدم الخاصة بك والمحرك التحميل المسبق.
1. إضافة عناصر الوسائط
أثناء ملء خلاصتك ، يجب عليك إبلاغ مدير الوسائط التي يحتاجها إلى تتبعها. إذا كنت تبدأ ، فيمكنك إضافة القائمة بأكملها التي تريد التحميل المسبق. بعد ذلك ، يمكنك الاستمرار في إضافة عنصر واحد إلى القائمة عند الاقتضاء. لديك سيطرة كاملة على العناصر الموجودة في قائمة التحميل المسبقة مما يعني أنه يتعين عليك أيضًا إدارة ما يتم إضافته وإزالته من المدير.
val initialMediaItems = pullMediaItemsFromService(/* count= */ 20) for (index in 0 until initialMediaItems.size) { preloadManager.add( initialMediaItems.get(index),index) ) }
سيبدأ المدير الآن في جلب البيانات لهذا الغرض ميديتيم في الخلفية.
بعد الإضافة ، أخبر المدير بإعادة تقييم قائمته الجديدة (مما يلمح إلى أن شيئًا ما قد تغير مثل إضافة/ إزالة عنصر ما ، أو مفاتيح المستخدم لتشغيل عنصر جديد.)
preloadManager.invalidate()
2. استرداد وتشغيل عنصر
هنا يأتي منطق التشغيل الرئيسي. عندما يقرر المستخدم تشغيل هذا الفيديو ، لا تحتاج إلى إنشاء جديد MediSource. بدلاً من ذلك ، تسأل Preloadmanager لتلك التي أعددها بالفعل. يمكنك استرداد MediSource من مدير التحميل المسبق باستخدام MediaItem.
إذا كان العنصر الذي تم استرداده من preloadmanager فارغًا ، فهذا يعني أن MediaItem لم يتم تحميله مسبقًا بعد أو تمت إضافته إلى preloadmamager ، لذلك اخترت تعيين MediaItem مباشرة.
// 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()
من خلال إعداد MediSource الذي تم استرجاعه من المسبق المسبق ، يمكنك الانتقال بسلاسة من التحميل المسبق إلى التشغيل ، باستخدام البيانات الموجودة بالفعل في الذاكرة. هذا ما يجعل وقت البدء أسرع.
3. حافظ على الفهرس الحالي متزامن مع واجهة المستخدم
نظرًا لأن قائمتنا / قائمتنا قد تكون ديناميكية ، فمن المهم إخطار المسبق لمؤشر التشغيل الحالي الخاص بك حتى يتمكن دائمًا من تحديد أولويات العناصر الأقرب إلى فهرسك الحالي من أجل التحميل المسبق.
preloadManager.setCurrentPlayingIndex(currentIndex) // Need to call invalidate() to update the priorities preloadManager.invalidate()
4. إزالة عنصر
للحفاظ على فعالية المدير ، يجب عليك إزالة العناصر التي لم تعد بحاجة إلى تتبعها ، مثل العناصر البعيدة عن الموضع الحالي للمستخدم.
// When an item is too far from the current playing index preloadManager.remove(mediaItem)
إذا كنت بحاجة إلى مسح جميع العناصر في وقت واحد ، فيمكنك استدعاء preloadmanager.reset ().
5. إطلاق سراح المدير
عندما لم تعد بحاجة إلى المسبق المسبق (على سبيل المثال ، عند تدمير واجهة المستخدم الخاصة بك) ، يجب عليك إطلاقها لتحرير مواردها. مكان جيد للقيام بذلك هو المكان الذي تطلق فيه بالفعل موارد اللاعب. يوصى بإصدار المدير قبل أن يتمكن اللاعب من الاستمرار في اللعب إذا لم تكن بحاجة إلى المزيد من التحميل المسبق.
// In your Activity's onDestroy() or Composable's onDispose preloadManager.release()
الوقت التجريبي
تحقق من ذلك مباشرة في العمل 👍
في العرض التوضيحي أدناه ، نرى تأثير PreloadManager على الجانب الأيمن الذي يحتوي على أوقات تحميل أسرع ، في حين يوضح الجانب الأيسر التجربة الحالية. يمكنك أيضًا عرض عينة الكود للتوضيح. (المكافأة: يعرض أيضًا زمن انتقال بدء التشغيل لكل مقطع فيديو)
![Jetpack Media3 API للتحميل السريع لمقاطع الفيديو القصيرة [PreloadManager]](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPRidTRe3s-2TIek6_YlfUsFwxRAaH-6rynAMXLX7UwVM9b-PhCAfOqAWwrTIBj6pSfntZizlYLU6nhmkNqbwwvBLGkWRjsOKNb-c56Jr8gutxBkSZidmOP1T420tBU5knaVvuAygMKHnDV8epXMc2TuIZN2klfnIKulNQUncwfz4fuuIlbLQ3yxhrhrU/s1600/Demo-PreloadManager%202.gif)
ماذا بعد؟
وهذا غلاف للجزء 1! لديك الآن الأدوات اللازمة لبناء نظام التحميل المسبق الديناميكي. يمكنك استخدام إما التكوين المسبق لتحميل العنصر التالي من قائمة التشغيل في Exoplayer أو إعداد أ DefaultPreloadManager، وأضف وإزالة العناصر الموجودة على الطيران ، وتكوين حالة التحميل المسبق المستهدف ، واسترداد المحتوى المسبق للتشغيل بشكل صحيح.
في الجزء 2، سنتعمق أكثر في DefaultPreloadManager. سنستكشف كيفية الاستماع إلى الأحداث المسبقة ، ونناقش أفضل الممارسات مثل استخدام نافذة انزلاقية لتجنب مشكلات الذاكرة ، وإلقاء نظرة خاطفة على غطاء محرك السيارة في مكونات مخصصة من Exoplayer و DefaultPreloadManager.
هل لديك أي تعليقات للمشاركة؟ نحن حريصون على سماع منك.
ترقبوا ، واذهب اجعل تطبيقك أسرع! 🚀

