الاستماع إلى أحداث التشغيل
يتم الإبلاغ عن الأحداث، مثل التغييرات التي تطرأ على الحالة وأخطاء التشغيل، إلى السجلات المُسجّلة.
Player.Listener
مثال. لتسجيل مستمع كي يتلقى
الأحداث:
Kotlin
// Add a listener to receive events from the player. player.addListener(listener)
Java
// Add a listener to receive events from the player. player.addListener(listener);
تتضمن Player.Listener
طُرقًا تلقائية فارغة، لذلك عليك فقط تنفيذها.
الأساليب التي تهتم بها. راجع Javadoc للحصول على وصف كامل
الطرق ووقت استدعائها. من أهم الطرق
بمزيد من التفصيل أدناه.
يمكن للمستمعين الاختيار بين تنفيذ عمليات استدعاء حدث فردية أو
استدعاء onEvents
عام يتم استدعاؤه بعد وقوع حدث واحد أو أكثر
يمكنك الانتقال إلى Individual callbacks vs onEvents
للحصول على شرح عن
تفضيلاً لحالات الاستخدام المختلفة.
تغيُّر حالة التشغيل
يمكن تلقّي التغييرات في حالة المشغّل من خلال التنفيذ
onPlaybackStateChanged(@State int state)
في حساب
Player.Listener
يمكن أن يكون المشغّل في إحدى حالات التشغيل الأربع:
Player.STATE_IDLE
: هذه هي الحالة الأولية، أي الحالة التي يكون فيها المشغّل توقف، وعند إخفاق التشغيل. لن يحتفظ اللاعب إلا بموارد محدودة. في هذه الحالة.Player.STATE_BUFFERING
: لا يمكن للمشغل التشغيل فورًا من خلال الموضع الحالي. يحدث هذا غالبًا بسبب الحاجة إلى تحميل المزيد من البيانات.Player.STATE_READY
: يستطيع اللاعب التشغيل فورًا بدءًا من الوضع الحالي الموقع.Player.STATE_ENDED
: انتهى المشغّل من تشغيل جميع الوسائط.
بالإضافة إلى هذه الحالات، يكون لدى اللاعب علامة playWhenReady
للإشارة إلى
نية المستخدم في اللعب. يمكن تلقي التغييرات في هذه العلامة من خلال التنفيذ
onPlayWhenReadyChanged(playWhenReady, @PlayWhenReadyChangeReason int reason)
يلعب أحد اللاعبين (أي أن موضعه يتقدم ويتم تشغيل الوسائط يتم تقديمه للمستخدم) عند استيفاء جميع الشروط الثلاثة التالية:
- المشغّل في حالة
Player.STATE_READY
- سيُقام
playWhenReady
true
- لا يتم منع التشغيل لسبب تم إرجاعه إلى
Player.getPlaybackSuppressionReason
بدلاً من الاضطرار إلى التحقّق من هذه السمات بشكلٍ فردي، يمكن Player.isPlaying
طلب البيانات. يمكن تلقّي التغييرات التي تطرأ على هذه الحالة من خلال التنفيذ.
onIsPlayingChanged(boolean isPlaying)
:
Kotlin
player.addListener( object : Player.Listener { override fun onIsPlayingChanged(isPlaying: Boolean) { if (isPlaying) { // Active playback. } else { // Not playing because playback is paused, ended, suppressed, or the player // is buffering, stopped or failed. Check player.playWhenReady, // player.playbackState, player.playbackSuppressionReason and // player.playerError for details. } } } )
Java
player.addListener( new Player.Listener() { @Override public void onIsPlayingChanged(boolean isPlaying) { if (isPlaying) { // Active playback. } else { // Not playing because playback is paused, ended, suppressed, or the player // is buffering, stopped or failed. Check player.getPlayWhenReady, // player.getPlaybackState, player.getPlaybackSuppressionReason and // player.getPlaybackError for details. } } });
أخطاء التشغيل
يمكن تلقّي الأخطاء التي تؤدي إلى تعذُّر التشغيل من خلال التنفيذ.
onPlayerError(PlaybackException error)
في حساب
Player.Listener
وعند حدوث إخفاق، سيتم استدعاء هذه الطريقة
قبل أن تنتقل حالة التشغيل إلى Player.STATE_IDLE
مباشرةً.
يمكن إعادة محاولة عمليات التشغيل التي تعذّر تشغيلها أو إيقافها من خلال الاتصال برقم ExoPlayer.prepare
.
تجدر الإشارة إلى أنّ بعض عمليات تنفيذ Player
تجتاز نُسخ من الفئات الفرعية
PlaybackException
لتقديم معلومات إضافية عن الخطأ. بالنسبة
على سبيل المثال، ExoPlayer
يجتاز ExoPlaybackException
، الذي يحتوي على type
،
rendererIndex
وحقول أخرى خاصة بـ ExoPlayer.
يوضح المثال التالي كيفية اكتشاف إخفاق عملية التشغيل بسبب مشكلة شبكة HTTP:
Kotlin
player.addListener( object : Player.Listener { override fun onPlayerError(error: PlaybackException) { val cause = error.cause if (cause is HttpDataSourceException) { // An HTTP error occurred. val httpError = cause // It's possible to find out more about the error both by casting and by querying // the cause. if (httpError is InvalidResponseCodeException) { // Cast to InvalidResponseCodeException and retrieve the response code, message // and headers. } else { // Try calling httpError.getCause() to retrieve the underlying cause, although // note that it may be null. } } } } )
Java
player.addListener( new Player.Listener() { @Override public void onPlayerError(PlaybackException error) { @Nullable Throwable cause = error.getCause(); if (cause instanceof HttpDataSourceException) { // An HTTP error occurred. HttpDataSourceException httpError = (HttpDataSourceException) cause; // It's possible to find out more about the error both by casting and by querying // the cause. if (httpError instanceof HttpDataSource.InvalidResponseCodeException) { // Cast to InvalidResponseCodeException and retrieve the response code, message // and headers. } else { // Try calling httpError.getCause() to retrieve the underlying cause, although // note that it may be null. } } } });
الانتقالات في قوائم التشغيل
عندما يتغير المشغّل إلى عنصر وسائط جديد في قائمة التشغيل
تم الاتصال برقم "onMediaItemTransition(MediaItem mediaItem,
@MediaItemTransitionReason int reason)
" في علامة التبويب "التسجيل"
Player.Listener
عناصر ويشير السبب إلى ما إذا كانت هذه العملية تلقائية
انتقال، أو التقديم (بعد استدعاء player.next()
مثلاً)، تكرار
العنصر نفسه، أو ناتجًا عن تغيير في قائمة التشغيل (على سبيل المثال، إذا كانت
تتم إزالة عنصر التشغيل).
البيانات الوصفية
يمكن أن تتغيّر البيانات الوصفية التي يتم عرضها من خلال player.getCurrentMediaMetadata()
بسبب عدة عوامل
الأسباب: عمليات نقل قوائم التشغيل أو تحديثات البيانات الوصفية ضمن البث المباشر أو تحديث
التشغيل الحالي لموسيقى MediaItem
أثناء التشغيل
إذا كنت مهتمًا بتغيير البيانات الوصفية، مثلاً لتعديل واجهة مستخدم تعرض
العنوان الحالي، يمكنك الاستماع إلى onMediaMetadataChanged
.
جارٍ تفعيل عناصر الانتقال
يؤدي استدعاء Player.seekTo
طريقة إلى إنشاء سلسلة من معاودة الاتصال إلى الحساب المسجّل.
Player.Listener
مثال:
- "
onPositionDiscontinuity
" مع "reason=DISCONTINUITY_REASON_SEEK
" هذا هو النتيجة المباشرة لاستدعاءPlayer.seekTo
. مدة معاودة الاتصالPositionInfo
الحقول الخاصة بالموضع قبل التقديم وبعده. onPlaybackStateChanged
مع أي تغيير فوري في الحالة مرتبط بالطلب تجدر الإشارة إلى أنّه قد لا يحدث هذا التغيير.
عمليات معاودة الاتصال الفردية مقابل onEvents
يمكن للمستمعين الاختيار بين تنفيذ استدعاءات فردية مثل
onIsPlayingChanged(boolean isPlaying)
والتصنيف العام
معاودة الاتصال onEvents(Player player, Events events)
. توفر معاودة الاتصال العامة
إمكانية الوصول إلى الكائن Player
وتحديد مجموعة events
التي حدثت
ويتم استدعاء هذه الدالة دائمًا بعد عمليات الاسترداد التي تتوافق مع
للأحداث الفردية.
Kotlin
override fun onEvents(player: Player, events: Player.Events) { if ( events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) || events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED) ) { uiModule.updateUi(player) } }
Java
@Override public void onEvents(Player player, Events events) { if (events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) || events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED)) { uiModule.updateUi(player); } }
يجب تفضيل الأحداث الفردية في الحالات التالية:
- المستمع مهتم بأسباب التغييرات. على سبيل المثال،
تم تقديم الأسباب وراء
onPlayWhenReadyChanged
أوonMediaItemTransition
. - لا يتعامل المستمع إلا مع القيم الجديدة المقدّمة من خلال مَعلمات معاودة الاتصال أو يؤدي إلى تشغيل شيء آخر لا يعتمد على معلمات معاودة الاتصال.
- يفضل تنفيذ المستمع إشارة واضحة ومقروءة لما أدى إلى تشغيل الحدث في اسم الطريقة.
- يقدم المستمع تقاريره إلى نظام تحليلي يحتاج إلى معرفة كل الأحداث الفردية وتغييرات الحالة.
يجب تفضيل onEvents(Player player, Events events)
العامة في
في الحالات التالية:
- يريد المستمع تشغيل المنطق نفسه لأحداث متعددة. بالنسبة
على سبيل المثال، تحديث واجهة المستخدم لكل من
onPlaybackStateChanged
onPlayWhenReadyChanged
- يحتاج المستمع إلى الوصول إلى كائن
Player
لتشغيل أحداث أخرى، مثل التقديم أو الترجيع بعد الانتقال إلى عنصر وسائط - المستمع يريد استخدام قيم حالة متعددة يتم الإبلاغ عنها
من خلال عمليات معاودة الاتصال منفصلة معًا، أو مع استدعاء واحد (
Player
) الطرق. على سبيل المثال، يؤدي استخدامPlayer.getCurrentWindowIndex()
مع السمةTimeline
المُدخل فيonTimelineChanged
آمن فقط من داخل معاودة الاتصال على "onEvents
" - يكون المستمع مهتم بما إذا كانت الأحداث قد وقعت معًا منطقيًا. بالنسبة
مثال، من
onPlaybackStateChanged
إلىSTATE_BUFFERING
بسبب ملف وسائط انتقالي.
في بعض الحالات، قد يحتاج المستمعون إلى دمج معاودة الاتصال الفردية مع
استدعاء onEvents
عام، مثلاً لتسجيل أسباب تغيير عنصر الوسائط
مع onMediaItemTransition
، ولكن يجب اتخاذ إجراء عند استخدام جميع تغييرات الحالة
معًا في onEvents
.
جارٍ استخدام AnalyticsListener
عند استخدام لعبة "ExoPlayer
"، يمكن تسجيل AnalyticsListener
مع اللاعب.
عبر الاتصال بـ addAnalyticsListener
. يمكن تنفيذ AnalyticsListener
للاستماع إلى الأحداث التفصيلية التي قد تكون مفيدة للإحصاءات والتسجيل
الأهداف. يُرجى الرجوع إلى صفحة الإحصاءات للاطّلاع على المزيد من التفاصيل.
جارٍ استخدام EventLogger
EventLogger
هو AnalyticsListener
الذي تقدمه المكتبة مباشرةً
لأغراض التسجيل. يمكنك إضافة EventLogger
إلى ExoPlayer
لتفعيل الميزة.
التسجيل الإضافي بسطر واحد:
Kotlin
player.addAnalyticsListener(EventLogger())
Java
player.addAnalyticsListener(new EventLogger());
راجِع صفحة تسجيل تصحيح الأخطاء للحصول على مزيد من التفاصيل.
تنشيط الأحداث في مواضع تشغيل محدّدة
تتطلب بعض حالات الاستخدام تنشيط أحداث في مواضع تشغيل محدّدة. هذا هو
متوفِّر باستخدام PlayerMessage
. يمكن إنشاء PlayerMessage
باستخدام
ExoPlayer.createMessage
موضع التشغيل الذي يجب تنفيذه
يمكن ضبطها باستخدام PlayerMessage.setPosition
. يتم تنفيذ الرسائل على
تشغيل الموضوع افتراضيًا، ولكن يمكن تخصيص هذا باستخدام
PlayerMessage.setLooper
يمكن استخدام PlayerMessage.setDeleteAfterDelivery
للتحكّم في ما إذا كان سيتم تنفيذ الرسالة في كل مرة
تمت مواجهة موضع تشغيل (قد يحدث هذا عدة مرات بسبب التقديم/الترجيع)
وأوضاع التكرار) أو في المرة الأولى فقط. بعد تحديد قيمة السمة PlayerMessage
تم إعداده، يمكن جدولته باستخدام PlayerMessage.send
.
Kotlin
player .createMessage { messageType: Int, payload: Any? -> } .setLooper(Looper.getMainLooper()) .setPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 120000) .setPayload(customPayloadData) .setDeleteAfterDelivery(false) .send()
Java
player .createMessage( (messageType, payload) -> { // Do something at the specified playback position. }) .setLooper(Looper.getMainLooper()) .setPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 120_000) .setPayload(customPayloadData) .setDeleteAfterDelivery(false) .send();