Oynatıcının durumunda yapılan değişiklikler (ör. oynatmanın başlatılması, arabelleğe alma veya hatalar), kayıtlı Player.Listener örneklerine gönderilen etkinlikleri tetikler. Bu etkinlikler, tam sayı sabitleriyle gösterilir ve Player.Event ile Player.Events tarafından tanımlanır.
Player.Listener kaydetme
Oynatıcı etkinlikleri, kayıtlı Player.Listener örneklerine bildirilir. Bu tür etkinlikleri almak için bir işleyici kaydetmek üzere:
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);
Kotlin kullanıyorsanız media3-common-ktx modülü tarafından sağlanan askıya alma uzantısı işlevlerini de kullanarak eşzamanlı rutinler aracılığıyla etkinlikleri dinleyebilirsiniz.
Bu durumda, Player.Listener
kaydetmeniz veya kaydını silmeniz gerekmez.
Player.Listener kullanarak oynatma etkinliklerini dinleme
Player.Listener, boş varsayılan yöntemlere sahiptir. Bu nedenle yalnızca ilgilendiğiniz yöntemleri uygulamanız gerekir. Yöntemlerin ve ne zaman çağrıldıklarının tam açıklaması için Javadoc'e bakın. En önemli yöntemlerden bazıları aşağıda daha ayrıntılı olarak açıklanmıştır.
Dinleyiciler, tek tek etkinlik geri çağırmalarını veya bir ya da daha fazla etkinlik birlikte gerçekleştiğinde çağrılan genel bir onEvents geri çağırmayı uygulayabilir. Farklı kullanım alanlarında hangisinin tercih edilmesi gerektiğiyle ilgili açıklama için Individual callbacks vs onEvents bölümüne bakın.
Oynatma durumu değişiklikleri
Oynatıcı durumundaki değişiklikler, kayıtlı bir Player.Listener içinde onPlaybackStateChanged(@State int state) uygulanarak alınabilir.
Oynatıcı, dört oynatma durumundan birinde olabilir:
Player.STATE_IDLE: Bu, başlangıç durumu, oynatıcı durdurulduğundaki durum ve oynatma başarısız olduğundaki durumdur. Oynatıcı bu durumda yalnızca sınırlı kaynak tutar.Player.STATE_BUFFERING: Oynatıcı, mevcut konumundan hemen oynatmaya başlayamıyor. Bu durumun temel nedeni, daha fazla verinin yüklenmesi gerekmesidir.Player.STATE_READY: Oynatıcı, mevcut konumundan hemen oynatmaya başlayabilir.Player.STATE_ENDED: Oynatıcı, tüm medyaları oynatmayı tamamladı.
Bu durumların yanı sıra, oynatıcıda kullanıcının oynatma isteğini belirtmek için playWhenReady işareti bulunur. Bu işaretle ilgili değişiklikler, onPlayWhenReadyChanged(playWhenReady, @PlayWhenReadyChangeReason int reason) uygulanarak alınabilir.
Aşağıdaki üç koşulun tümü karşılandığında bir oynatıcı oynatılıyor (yani konumu ilerliyor ve kullanıcıya medya sunuluyor) demektir:
- Oyuncu
Player.STATE_READYdurumundadır. playWhenReady:true- Oynatma,
Player.getPlaybackSuppressionReasontarafından döndürülen bir nedenle engellenmiyor.
Bu özelliklerin tek tek kontrol edilmesi yerine Player.isPlaying
çağrılabilir. Bu durumdaki değişiklikler, onIsPlayingChanged(boolean isPlaying) uygulanarak alınabilir:
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. } } });
Oynatma hataları
Oynatmanın başarısız olmasına neden olan hatalar, kayıtlı bir Player.Listener içinde onPlayerError(PlaybackException error) uygulanarak alınabilir. Bir hata oluştuğunda bu yöntem, oynatma durumu Player.STATE_IDLE'ya geçmeden hemen önce çağrılır. Başarısız olan veya durdurulan oynatma işlemleri, ExoPlayer.prepare çağrılarak yeniden denenebilir.
Bazı Player uygulamalarının, başarısızlık hakkında ek bilgi sağlamak için PlaybackException alt sınıflarının örneklerini ilettiğini unutmayın. Örneğin, ExoPlayer, type, rendererIndex ve ExoPlayer'a özel diğer alanları içeren ExoPlaybackException'ı iletir.
Aşağıdaki örnekte, HTTP ağ iletişimi sorunu nedeniyle oynatmanın başarısız olduğu durumların nasıl tespit edileceği gösterilmektedir:
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. } } } });
Oynatma listesi geçişleri
Oynatma listesindeki yeni bir medya öğesine geçildiğinde, kayıtlı Player.Listener nesnelerinde onMediaItemTransition(MediaItem mediaItem, @MediaItemTransitionReason int
reason) çağrılır. Nedeni, bunun otomatik bir geçiş mi, arama mı (örneğin, player.next() arandıktan sonra), aynı öğenin tekrarı mı yoksa oynatma listesi değişikliğinden mi (örneğin, şu anda oynatılan öğe kaldırılırsa) kaynaklandığını gösterir.
Meta veri
player.getCurrentMediaMetadata()'dan döndürülen meta veriler birçok nedenden dolayı değişebilir: oynatma listesi geçişleri, akış içi meta veri güncellemeleri veya mevcut MediaItem'nın oynatma sırasında güncellenmesi.
Meta veri değişiklikleriyle ilgileniyorsanız (ör. mevcut başlığı gösteren bir kullanıcı arayüzünü güncellemek için) onMediaMetadataChanged dinleyebilirsiniz.
Oynatma konumu değiştiriliyor
Player.seekTo yöntemlerinin çağrılması, kayıtlı Player.Listener örneklerine yönelik bir dizi geri çağırmayla sonuçlanır:
reason=DISCONTINUITY_REASON_SEEKileonPositionDiscontinuity. Bu,Player.seekToişlevinin doğrudan sonucudur. Geri çağırma işlevinde, arama işleminden önceki ve sonraki konum içinPositionInfoalanları bulunur.- Arama işlemiyle ilgili anlık durum değişikliğiyle
onPlaybackStateChanged. Böyle bir değişiklik olmayabilir.
Bireysel geri aramalar ve onEvents
Dinleyiciler, onIsPlayingChanged(boolean isPlaying) gibi tek tek geri çağırmaları ve genel onEvents(Player
player, Events events) geri çağırmayı kullanabilir. Genel geri arama, Player nesnesine erişim sağlar ve birlikte gerçekleşen events kümesini belirtir. Bu geri çağırma, her zaman tek tek etkinliklere karşılık gelen geri çağırmalardan sonra çağrılır.
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); } }
Aşağıdaki durumlarda bağımsız etkinlikler tercih edilmelidir:
- Dinleyici, değişikliklerin nedenleriyle ilgileniyor. Örneğin,
onPlayWhenReadyChangedveyaonMediaItemTransitioniçin sağlanan nedenler. - Dinleyici yalnızca geri çağırma parametreleri aracılığıyla sağlanan yeni değerlere göre hareket eder veya geri çağırma parametrelerine bağlı olmayan başka bir şeyi tetikler.
- Dinleyici uygulaması, yöntem adında etkinliği neyin tetiklediğine dair net ve okunabilir bir göstergeyi tercih eder.
- Dinleyici, tüm bireysel etkinlikler ve durum değişiklikleri hakkında bilgi sahibi olması gereken bir analiz sistemine rapor gönderir.
Aşağıdaki durumlarda genel onEvents(Player player, Events events) tercih edilmelidir:
- Dinleyici, birden fazla etkinlik için aynı mantığı tetiklemek istiyor. Örneğin, hem
onPlaybackStateChangedhem deonPlayWhenReadyChangediçin kullanıcı arayüzünü güncelleme. - Dinleyicinin, başka etkinlikleri tetiklemek için
Playernesnesine erişmesi gerekir. Örneğin, medya öğesi geçişinden sonra arama yapma. - Dinleyici, ayrı geri çağırma işlevleri aracılığıyla bildirilen birden fazla durum değerini birlikte veya
Playergetter yöntemleriyle birlikte kullanmayı planlıyor. Örneğin,onTimelineChangediçinde sağlananTimelineilePlayer.getCurrentWindowIndex()kullanmak yalnızcaonEventsgeri çağırma işlevi içinde güvenlidir. - Dinleyici, etkinliklerin mantıksal olarak birlikte gerçekleşip gerçekleşmediğiyle ilgilenir.
Örneğin, bir medya öğesi geçişi nedeniyle
onPlaybackStateChangedileSTATE_BUFFERINGarasında.
Bazı durumlarda dinleyicilerin, tek tek geri aramaları genel onEvents geri aramasıyla birleştirmesi gerekebilir. Örneğin, medya öğesi değişikliği nedenlerini onMediaItemTransition ile kaydetmek için. Ancak yalnızca tüm durum değişiklikleri onEvents içinde birlikte kullanılabildiğinde işlem yapılabilir.
Eş yordamları kullanarak oynatma etkinliklerini dinleme
Alternatif olarak, Player.listenTo kullanarak bir Kotlin eş yordamı başlatabilir ve ilgili Player.Event'ı belirtebilirsiniz:
Player.listen ve Player.listenTo'ın herhangi bir iş parçacığından çağrılabileceğini, geri çağırma lambdasının ise her zaman Player.getApplicationLooper ile ilişkili iş parçacığında çağrıldığını unutmayın. Bu nedenle, eş yordam farklı bir iş parçacığında başlatılmış olsa bile geri çağırma lambda'sının içindeki Player
yöntemlerine ve durum özelliklerine erişmek güvenlidir.
Oynatma durumu değişiklikleri
coroutineScope.launch { player.listenTo(Player.EVENT_IS_PLAYING_CHANGED) { // `Player` is a receiver scope for this trailing lambda if (isPlaying) { // Active playback. } else { // Not playing. } } }
Oynatma hataları
coroutineScope.launch { player.listenTo(Player.EVENT_PLAYER_ERROR) { val error = playerError ?: return@listenTo val cause = error.cause if (cause is HttpDataSourceException) { // An HTTP error occurred. if (cause is InvalidResponseCodeException) { // Retrieve the response code, message and headers } else { // Try calling cause.cause to retrieve the underlying cause } } } }
Bireysel geri aramalar ve onEvents
Bir coroutine içinde oynatıcı etkinliklerini dinlerken her zaman tek bir geri çağırma yerine onEvents geri çağırması için uygulama sağlayacaksınız. Hangi etkinliklerin lambda işlevinizin çağrılmasını tetiklemesi gerektiğine bağlı olarak Player.listen ve Player.listenTo arasında seçim yapabilirsiniz. Ancak işlevler başka açılardan eşdeğerdir:
dinle
coroutineScope.launch { player.listen { events -> // `Player` is a receiver scope for this trailing lambda if (events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED)) { // Access the player state directly from the receiver updateUi(playbackState) } if (events.contains(Player.EVENT_PLAYER_ERROR)) { // Access the error directly from the player handleError(playerError) } } }
listenTo
coroutineScope.launch { player.listenTo(Player.EVENT_PLAYBACK_STATE_CHANGED, Player.EVENT_PLAYER_ERROR) { events -> // `Player` is a receiver scope for this trailing lambda if (events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED)) { // Access the player state directly from the receiver updateUi(playbackState) } if (events.contains(Player.EVENT_PLAYER_ERROR)) { // Access the error directly from the player handleError(playerError) } } }
Birden fazla etkinlik türüyle ilgileniyorsanız Player.listenTo işlevine etkinlik listesi iletebilirsiniz. Bu etkinliklerden herhangi biri gerçekleştiğinde lambda'nız çağrılır ve hangi etkinliklerin gerçekten tetiklendiğini kontrol etmek için Events parametresini inceleyebilirsiniz:
coroutineScope.launch { player.listenTo(Player.EVENT_PLAYBACK_STATE_CHANGED, Player.EVENT_PLAYER_ERROR) { events -> // Unclear which event got triggered without querying `events` parameter // The following function will fire whenever either one is caught updateUiAndHandleError(playbackState, playerError) } }
Bu işlevler onEvents üzerinde çalıştığından, onMediaItemTransition(..., int reason) içindeki neden veya onPositionDiscontinuity(...) içindeki oldPosition gibi tek tek geri çağırmalara iletilen geçici bağımsız değişkenlere erişim sağlamaz. Mantığınız bu belirli bağımsız değişkenlere bağlıysa
(ve bunlar Player üzerinde durum özellikleri olarak kullanılamıyorsa) bunun yerine standart Player.Listener arayüzünü kullanmanız gerekir.
AnalyticsListener cihazını kullan
ExoPlayer kullanılırken addAnalyticsListener aranarak oynatıcıya AnalyticsListener kaydedilebilir. AnalyticsListener uygulamaları, analiz ve günlük kaydı amacıyla kullanılabilecek ayrıntılı etkinlikleri dinleyebilir. Daha fazla bilgi için lütfen analizler sayfasını inceleyin.
EventLogger cihazını kullan
EventLogger, günlük kaydı amacıyla doğrudan kitaplık tarafından sağlanan bir AnalyticsListener'dır. Tek bir satırla yararlı ek günlük kaydını etkinleştirmek için EventLogger öğesini ExoPlayer öğesine ekleyin:
Kotlin
player.addAnalyticsListener(EventLogger())
Java
player.addAnalyticsListener(new EventLogger());
Daha fazla ayrıntı için hata ayıklama günlük kaydı sayfasına bakın.
Belirtilen oynatma konumlarında etkinlikleri tetikleme
Bazı kullanım alanlarında, etkinliklerin belirli oynatma konumlarında tetiklenmesi gerekir. Bu özellik, PlayerMessage kullanılarak desteklenir. PlayerMessage, ExoPlayer.createMessage kullanılarak oluşturulabilir. Yürütülmesi gereken oynatma konumu PlayerMessage.setPosition kullanılarak ayarlanabilir. İletiler varsayılan olarak oynatma iş parçacığında yürütülür ancak bu, PlayerMessage.setLooper kullanılarak özelleştirilebilir. PlayerMessage.setDeleteAfterDelivery, belirtilen oynatma konumu her karşılaşıldığında (arama ve tekrar modları nedeniyle bu durum birden çok kez gerçekleşebilir) mesajın yürütülüp yürütülmeyeceğini veya yalnızca ilk kez yürütülüp yürütülmeyeceğini kontrol etmek için kullanılabilir. PlayerMessage yapılandırıldıktan sonra PlayerMessage.send kullanılarak planlanabilir.
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();