أخبار المنتجات
تحسين تشغيل الوسائط: تقديم ميزة التحميل المُسبق باستخدام 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 مصمّم خصيصًا للتحميل المُسبق بشكل استباقي. يدير هذا المكوّن مجموعة من `MediaSources` المحتملة، ويمنحها الأولوية استنادًا إلى مدى قربها من موضع المستخدم الحالي، ويوفر تحكّمًا دقيقًا في المحتوى الذي سيتم تحميله مسبقًا، ما يجعله مناسبًا للسيناريوهات المعقّدة، مثل الخلاصات الديناميكية للفيديوهات القصيرة.
إعداد `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()
هذا كل ما في الأمر! أصبح لديك الآن مدير جاهز لتلقّي التعليمات.
ضبط المدة والترتيب باستخدام TargetPreloadStatusControl
ماذا لو أردت تحميل 10 ثوانٍ من الفيديو مسبقًا؟ يمكنك تقديم موضع عناصر الوسائط في لوحة العرض الدوّارة، ويمنح `DefaultPreloadManager` الأولوية لتحميل العناصر استنادًا إلى مدى قربها من العنصر الذي يشغّله المستخدم حاليًا.
إذا أردت التحكّم في مدة العنصر الذي سيتم تحميله مسبقًا، يمكنك إخبار `DefaultPreloadManager` بذلك باستخدام `PreloadStatus` الذي تعرضه.
على سبيل المثال:
- العنصر "أ" هو الأولوية القصوى، يتم تحميل 5 ثوانٍ من الفيديو.
- العنصر "ب" هو أولوية متوسطة، ولكن عند الوصول إليه، يتم تحميل 3 ثوانٍ من الفيديو.
- العنصر "ج" هو أولوية أقل، يتم تحميل المسارات فقط.
- العنصر "د" هو أولوية أقل، يتم إعداده فقط.
- أي عناصر أخرى بعيدة، لا يتم تحميل أي محتوى مسبقًا.
يمكن أن يساعدك هذا التحكّم الدقيق في تحسين استخدام الموارد، وهو ما يُنصح به لتشغيل سلس.
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` من `PreloadManager` باستخدام `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. إيقاف المدير
عندما لا تعود بحاجة إلى `PreloadManager` (مثلاً، عند إيقاف واجهة المستخدم)، عليك إيقافه لتحرير موارده. المكان المناسب لإجراء ذلك هو المكان الذي توقف فيه موارد المشغّل. يُنصح بإيقاف المدير قبل المشغّل لأنّه يمكن أن يستمر في التشغيل إذا لم تعُد بحاجة إلى أي تحميل مُسبق.
// In your Activity's onDestroy() or Composable's onDispose preloadManager.release()
تقديم العرض التوضيحي
يمكنك الاطّلاع على طريقة استخدام هذه الميزة عمليًا 👍
في العرض التوضيحي أدناه ، نرى تأثير `PreloadManager` على الجانب الأيمن الذي يتميز بأوقات تحميل أسرع، بينما يعرض الجانب الأيسر التجربة الحالية. يمكنك أيضًا الاطّلاع على نموذج الرمز البرمجي sample للعرض التوضيحي. (مكافأة: يعرض أيضًا وقت استجابة بدء التشغيل لكل فيديو)
الخطوات التالية:
وهذا ختام الجزء الأول! أصبحت لديك الآن الأدوات اللازمة لإنشاء نظام تحميل مُسبق ديناميكي. يمكنك إما استخدام PreloadConfiguration لتحميل العنصر التالي من قائمة تشغيل مسبقًا في ExoPlayer أو إعداد DefaultPreloadManager، وإضافة العناصر وإزالتها أثناء التنقل، وضبط حالة التحميل المُسبق المستهدفة، واسترداد المحتوى الذي تم تحميله مسبقًا بشكل صحيح لتشغيله.
في الجزء 2، سنتناول DefaultPreloadManager بتفصيل أكبر. سنستكشف كيفية الاستماع إلى أحداث التحميل المُسبق، ونناقش أفضل الممارسات، مثل استخدام نافذة منزلقة لتجنُّب مشاكل الذاكرة، ونلقي نظرة على المكوّنات المخصّصة المشتركة في ExoPlayer و`DefaultPreloadManager`.
هل لديك أي ملاحظات لمشاركتها؟ نحن حريصون على سماع رأيك.
ترقَّبوا المزيد، وابدأوا في تسريع تطبيقكم. 🚀
متابعة القراءة
-
2025/09/222025/09/22
أخبار المنتجات
مرحبًا بك في الجزء الثاني من سلسلتنا المكوّنة من ثلاثة أجزاء حول التحميل المُسبق للوسائط باستخدام Media3. تم تصميم هذه السلسلة لإرشادك خلال عملية إنشاء تجارب وسائط سريعة الاستجابة ومنخفضة وقت الاستجابة في تطبيقات Android.
Mayuri Khinvasara Khabya • قراءة لمدة 9 دقائق
-
أخبار المنتجات
أصبح الإصدار 4 من استوديو Android Panda مستقرًا وجاهزًا للاستخدام في الإنتاج. يتضمّن هذا الإصدار "وضع التخطيط" و"توقّع التعديل التالي" والمزيد، ما يسهّل أكثر من أي وقت مضى إنشاء تطبيقات Android عالية الجودة.
Matt Dyor • قراءة لمدة 5 دقائق
-
أخبار المنتجات
إذا كنت مطوّر Android وتسعى إلى تنفيذ ميزات ذكاء اصطناعي مبتكرة في تطبيقك، فقد أطلقنا مؤخرًا تحديثات جديدة قوية.
Thomas Ezan • قراءة لمدة 3 دقائق
البقاء على اطّلاع على آخر التحديثات
يمكنك تلقّي أحدث الإحصاءات حول تطوير تطبيقات Android أسبوعيًا في بريدك الوارد.