تحسين تجربة تشغيل الوسائط: مقدّمة عن ميزة التحميل المُسبَق في Media3 - الجزء 1
مدّة القراءة: 8 دقائق
في تطبيقات الوسائط الحالية، يُعدّ توفير تجربة تشغيل سلسة ومتواصلة أمرًا أساسيًا لتقديم تجربة ممتعة للمستخدمين. يتوقّع المستخدمون أن تبدأ فيديوهاتهم على الفور وأن يتم تشغيلها بسلاسة بدون توقّف.
التحدي الأساسي هو وقت الاستجابة. في العادة، لا يبدأ مشغّل الفيديو عمله (الاتصال والتنزيل والتحليل والتخزين المؤقت) إلا بعد أن يختار المستخدم عنصرًا لتشغيله. هذا الأسلوب التفاعلي بطيء في سياق الفيديوهات القصيرة اليوم. الحل هو اتخاذ خطوات استباقية. علينا توقّع المحتوى الذي سيشاهده المستخدم بعد ذلك وتجهيزه مسبقًا. هذه هي فكرة التحميل المُسبَق.
تشمل المزايا الرئيسية للتحميل المُسبَق ما يلي:
- 🚀 بدء تشغيل أسرع: الفيديوهات جاهزة للتشغيل، ما يؤدي إلى انتقالات أسرع بين العناصر وبدء تشغيل فوري.
- 📉 تقليل التخزين المؤقت: من خلال تحميل البيانات بشكل استباقي، يصبح من غير المرجّح أن يتوقف التشغيل مؤقتًا، مثلاً بسبب مشاكل في الشبكة.
- ✨ تجربة مستخدم أكثر سلاسة: يساهم الجمع بين سرعة بدء التشغيل وتقليل التخزين المؤقت في توفير تفاعل أكثر سلاسة للمستخدمين.
في هذه السلسلة المكوّنة من ثلاثة أجزاء، سنقدّم ونشرح بالتفصيل الأدوات المساعدة الفعّالة في Media3 لتحميل المكوّنات (مسبقًا).
- في الجزء 1، سنتناول الأساسيات: فهم استراتيجيات التحميل المُسبَق المختلفة المتوفّرة في Media3، وتفعيل PreloadConfiguration وإعداد DefaultPreloadManager، وإتاحة التحميل المُسبَق للعناصر في تطبيقك. في نهاية هذه المدونة، من المفترض أن تتمكّن من التحميل المُسبَق لعناصر الوسائط وتشغيلها حسب الترتيب والمدة المحدّدين.
- في الجزء 2، سنتناول مواضيع أكثر تقدّمًا حول DefaultPreloadManager: استخدام أدوات معالجة الأحداث للإحصاءات، واستكشاف أفضل الممارسات الجاهزة للاستخدام في مرحلة الإنتاج، مثل نمط النافذة المنزلقة والمكوّنات المخصّصة المشترَكة في DefaultPreloadManager وExoPlayer.
- في الجزء 3، سنتعمّق في التخزين المؤقت على القرص باستخدام DefaultPreloadManager.
التحميل المُسبق هو الحلّ! 🦸♀️
الفكرة الأساسية من التحميل المُسبَق بسيطة: تحميل محتوى الوسائط قبل الحاجة إليه. عندما يمرّر المستخدم سريعًا إلى الفيديو التالي، تكون المقاطع الأولى من الفيديو قد تم تنزيلها وتكون متاحة، وجاهزة للتشغيل الفوري.
فكِّر في الأمر كأنّك في مطعم. لا ينتظر المطبخ المزدحم وصول الطلب لبدء تقطيع البصل. 🧅 ينجزون أعمالهم التحضيرية مسبقًا. التحميل المُسبق هو عملية تحضير مشغّل الفيديو.
عند تفعيل ميزة التحميل المُسبَق، يمكن أن تساعد في تقليل وقت الاستجابة عند الانضمام عندما ينتقل المستخدم إلى العنصر التالي قبل أن تصل مدة التخزين المؤقت للتشغيل إلى العنصر التالي. يتم إعداد الفترة الأولى من النافذة التالية وتخزين عيّنات الفيديو والصوت والنص مؤقتًا. يتم بعد ذلك وضع فترة التحميل المُسبَق في قائمة الانتظار في المشغّل مع توفّر عيّنات مخزّنة مؤقتًا على الفور وجاهزة ليتم إدخالها إلى برنامج الترميز لتقديمها.
في Media3، تتوفّر واجهتا برمجة تطبيقات أساسيتان للتحميل المُسبَق، وكلّ منهما مناسبة لحالات استخدام مختلفة. اختيار واجهة برمجة التطبيقات المناسبة هو الخطوة الأولى.
1. التحميل المُسبَق لعناصر قائمة التشغيل باستخدام PreloadConfiguration
هذه هي الطريقة البسيطة، وهي مفيدة للوسائط الخطية والتسلسلية، مثل قوائم التشغيل التي يمكن توقّع ترتيب تشغيلها (مثل سلسلة من الحلقات). يمكنك تزويد اللاعب بالقائمة الكاملة لعناصر الوسائط باستخدام واجهات برمجة التطبيقات لقوائم التشغيل في ExoPlayer وضبط PreloadConfiguration للمشغّل، ثم سيتم تلقائيًا التحميل المُسبَق للعناصر التالية في التسلسل على النحو الذي تم ضبطه. تحاول واجهة برمجة التطبيقات هذه تحسين وقت الاستجابة للانضمام عندما ينتقل المستخدم إلى العنصر التالي قبل أن تتداخل مخزن التشغيل المؤقت مع العنصر التالي.
لا تبدأ عملية التحميل المُسبَق إلا عندما لا يتم تحميل أي وسائط للتشغيل الجاري، ما يمنعها من التنافس على النطاق الترددي مع عملية التشغيل الأساسية.
إذا لم تكن متأكّدًا بعدُ مما إذا كنت بحاجة إلى التحميل المُسبَق، تُعدّ واجهة برمجة التطبيقات هذه خيارًا رائعًا وسهلاً لتجربته.
player.preloadConfiguration =
PreloadConfiguration(/* targetPreloadDurationUs= */ 5_000_000L)باستخدام PreloadConfiguration أعلاه، يحاول المشغّل التحميل المُسبَق لمدّة خمس ثوانٍ من الوسائط للعنصر التالي في قائمة التشغيل.
بعد الموافقة على هذه الميزة، يمكن إيقافها مجددًا باستخدام PreloadConfiguration.DEFAULT لإيقاف التحميل المُسبَق لقوائم التشغيل:
player.preloadConfiguration = PreloadConfiguration.DEFAULT
2. التحميل المُسبَق للقوائم الديناميكية باستخدام PreloadManager
بالنسبة إلى واجهات المستخدم الديناميكية، مثل الخلاصات العمودية أو اللوحات الدوّارة، حيث يتم تحديد العنصر "التالي" من خلال تفاعل المستخدم، تكون واجهة برمجة التطبيقات PreloadManager مناسبة. هذا مكوّن جديد مستقل وفعّال ضمن مكتبة Media3 ExoPlayer مصمَّم خصيصًا للتحميل المُسبَق بشكل استباقي. تدير هذه الفئة مجموعة من مصادر الوسائط المحتملة، وتمنحها الأولوية استنادًا إلى مدى قربها من الموقع الجغرافي الحالي للمستخدم، وتوفّر تحكّمًا دقيقًا في المحتوى الذي سيتم تحميله مسبقًا، ما يجعلها مناسبة لحالات الاستخدام المعقّدة، مثل الخلاصات الديناميكية للفيديوهات القصيرة.
إعداد PreloadManager
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 ثوانٍ من الفيديو؟ يمكنك تقديم موضع عناصر الوسائط في لوحة العرض الدوّارة، وتحدّد أداة DefaultPreloadManager أولوية تحميل العناصر استنادًا إلى مدى قربها من العنصر الذي يشغّله المستخدم حاليًا.
إذا أردت التحكّم في مدة تحميل العنصر مسبقًا، يمكنك تحديد ذلك باستخدام DefaultPreloadManager.PreloadStatus الذي تعرضه.
على سبيل المثال:
- العنصر "أ" هو الأعلى أولوية، حمِّل 5 ثوانٍ من الفيديو.
- العنصر "ب" له أولوية متوسطة، ولكن عند الوصول إليه، يجب تحميل 3 ثوانٍ من الفيديو.
- العنصر "C" أقل أهمية، ويتم تحميل المسارات فقط.
- العنصر "د" أقل أهمية، لذا عليك الاستعداد فقط.
- إذا كانت أي عناصر أخرى بعيدة، لا تحمّل أي شيء مسبقًا.
يمكن أن يساعدك هذا التحكّم الدقيق في تحسين استخدام الموارد، وهو أمر يُنصح به لتشغيل الفيديو بسلاسة.
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 بالعناصر السابقة واللاحقة التي تم تحميلها مسبقًا، بينما ستبحث PreloadConfiguration فقط عن العناصر اللاحقة.
إدارة عناصر التحميل المُسبَق
بعد إنشاء المدير، يمكنك البدء بإخباره بالمهام التي يجب العمل عليها. أثناء تنقّل المستخدم في الخلاصة، يمكنك تحديد الفيديوهات القادمة وإضافتها إلى المدير. التفاعل مع PreloadManager هو محادثة مستندة إلى الحالة بين واجهة المستخدم ومحرك التحميل المُسبَق.
1. إضافة ملفات وسائط
أثناء ملء الخلاصة، يجب إبلاغ المدير بالوسائط التي يجب تتبُّعها. إذا كنت مبتدئًا، يمكنك إضافة القائمة الكاملة التي تريد التحميل المُسبَق لها. بعد ذلك، يمكنك مواصلة إضافة عنصر واحد إلى القائمة حسب الحاجة. يمكنك التحكّم بشكل كامل في العناصر المدرَجة في قائمة التحميل المُسبَق، ما يعني أنّه عليك أيضًا إدارة العناصر التي تتم إضافتها وإزالتها من المدير.
val initialMediaItems = pullMediaItemsFromService(/* count= */ 20)
for (index in 0 until initialMediaItems.size) {
preloadManager.add(
initialMediaItems.get(index),index)
)
}سيبدأ المدير الآن في جلب البيانات لهذا MediaItem في الخلفية.
بعد الإضافة، اطلب من المدير إعادة تقييم القائمة الجديدة (مع الإشارة إلى حدوث تغيير مثل إضافة عنصر أو إزالته، أو انتقال المستخدم إلى تشغيل عنصر جديد).
preloadManager.invalidate()
2. استرداد عنصر وتشغيله
إليك منطق التشغيل الرئيسي. عندما يقرّر المستخدم تشغيل هذا الفيديو، لن تحتاج إلى إنشاء MediaSource جديد. بدلاً من ذلك، يمكنك طلب PreloadManager الذي أعدّه مسبقًا. يمكنك استرداد MediaSource من Preload Manager باستخدام 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()من خلال إعداد MediaSource التي تم استردادها من PreloadManager، يمكنك الانتقال بسلاسة من التحميل المُسبَق إلى التشغيل، وذلك باستخدام البيانات المتوفّرة في الذاكرة. وهذا ما يجعل وقت البدء أسرع.
3. الحفاظ على مزامنة الفهرس الحالي مع واجهة المستخدم
بما أنّ الخلاصة أو القائمة قد تكون ديناميكية، من المهم إعلام PreloadManager بفهرس التشغيل الحالي لكي يتمكّن دائمًا من تحديد أولويات العناصر الأقرب إلى الفهرس الحالي للتحميل المُسبَق.
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. إصدار Manager
عندما لا تعود بحاجة إلى PreloadManager (على سبيل المثال، عند إيقاف واجهة المستخدم)، عليك إصداره لإتاحة موارده. يمكنك إجراء ذلك في المكان الذي تتيح فيه حاليًا موارد "مشغل التطبيقات". يُنصح بإصدار المدير قبل المشغّل لأنّ المشغّل يمكنه مواصلة التشغيل إذا لم تعُد بحاجة إلى أي تحميل مسبق.
// In your Activity's onDestroy() or Composable's onDispose preloadManager.release()
تقديم العرض التوضيحي
يمكنك الاطّلاع على طريقة استخدام هذه الميزة عمليًا 👍
في العرض التوضيحي أدناه، نرى تأثير PreloadManager على الجانب الأيسر الذي يتميّز بأوقات تحميل أسرع، بينما يعرض الجانب الأيمن التجربة الحالية. يمكنك أيضًا الاطّلاع على نموذج الرمز للعرض التوضيحي. (ميزة إضافية: يعرض أيضًا وقت استجابة بدء التشغيل لكل فيديو)
الخطوات التالية:
هذا كل ما لدينا في الجزء الأول. أصبحت لديك الآن الأدوات اللازمة لإنشاء نظام تحميل مسبق ديناميكي. يمكنك استخدام PreloadConfiguration لتحميل العنصر التالي في قائمة التشغيل مسبقًا في ExoPlayer أو إعداد DefaultPreloadManager وإضافة العناصر وإزالتها أثناء التنقل وتحديد حالة التحميل المسبق المستهدَفة واسترداد المحتوى المحمَّل مسبقًا بشكل صحيح لتشغيله.
في الجزء 2، سنتعمّق أكثر في DefaultPreloadManager. سنتعرّف على كيفية الاستماع إلى أحداث التحميل المُسبَق، وسنناقش أفضل الممارسات، مثل استخدام نافذة منزلقة لتجنُّب مشاكل الذاكرة، وسنلقي نظرة على المكوّنات المشترَكة المخصّصة في ExoPlayer وDefaultPreloadManager.
هل لديك أي ملاحظات تودّ مشاركتها؟ نتطلّع إلى تلقّي ردّك.
ننصحك بمتابعتنا لمعرفة المزيد قريبًا، ونشجّعك على العمل على تسريع تطبيقك. 🚀
-
أخبار المنتجاتمرحبًا بك في الجزء الثاني من سلسلتنا المكوّنة من ثلاثة أجزاء حول التحميل المُسبَق للوسائط باستخدام Media3. تم تصميم هذه السلسلة لإرشادك خلال عملية إنشاء تجارب وسائط سريعة الاستجابة ومنخفضة الكمون في تطبيقات Android.
Mayuri Khinvasara Khabya • مدّة القراءة: 9 دقائق -
أخبار المنتجاتعلى Google Play، نعمل باستمرار على توسيع منصة الاشتراكات لمساعدتك في تعزيز النمو والتكيّف مع نماذج الأعمال الجديدة وتلبية احتياجات المستخدمين أينما كانوا.
Sheenam Mittal • مدّة القراءة: 4 دقائق -
أخبار المنتجاتفي العام الماضي، أصبح بإمكان "استوديو Android" استخدام أي نموذج للذكاء الاصطناعي. واليوم، نتّخذ الخطوة التالية من خلال توفير إمكانية اختيار وكلاء الترميز.
Matthew Warner • مدّة القراءة: 3 دقائق
يمكنك تلقّي أحدث الإحصاءات حول تطوير تطبيقات Android في بريدك الوارد أسبوعيًا.