Ürün Haberleri
Medya oynatmayı geliştirme: Media3'ün PreloadManager'ı hakkında ayrıntılı inceleme - Bölüm 2
Okuma süresi: 9 dakika
Media3 ile medya önceden yükleme hakkındaki üç bölümlük serimizin ikinci bölümüne hoş geldiniz. Bu seri, Android uygulamalarınızda yüksek düzeyde duyarlı ve düşük gecikmeli medya deneyimleri oluşturma sürecinde size yol göstermek için tasarlanmıştır.
- 1. Bölüm: Media3 ile önceden yüklemeye giriş başlıklı makalede temel bilgiler verilmişti. Basit oynatma listeleri için PreloadConfiguration ile dinamik kullanıcı arayüzleri için daha güçlü olan DefaultPreloadManager arasındaki farkı inceledik. Temel API yaşam döngüsünü nasıl uygulayacağınızı öğrendiniz: add() ile medya ekleme, getMediaSource() ile hazırlanmış bir MediaSource'u alma, setCurrentPlayingIndex() ve invalidate() ile öncelikleri yönetme, remove() ve release() ile kaynakları serbest bırakma.
- 2. Bölüm (Bu yayın): Bu blogda, DefaultPreloadManager'ın gelişmiş özelliklerini ele alıyoruz. PreloadManagerListener ile nasıl analiz elde edeceğinizi, temel bileşenleri ExoPlayer ile paylaşma gibi üretime hazır en iyi uygulamaları nasıl uygulayacağınızı ve belleği etkili bir şekilde yönetmek için kayan pencere modelinde nasıl ustalaşacağınızı ele alıyoruz.
- 3. Bölüm: Bu serinin son bölümünde, PreloadManager'ı kalıcı disk önbelleğiyle entegre etme konusu ele alınacak. Böylece kaynak yönetimiyle veri tüketimini azaltıp sorunsuz bir deneyim sunabileceksiniz.
Media3'te önceden yükleme konusunda yeniyseniz devam etmeden önce 1. Bölüm'ü okumanızı önemle tavsiye ederiz. Temel bilgilerin ötesine geçmeye hazır olanlar için medya oynatma uygulamanızı nasıl geliştirebileceğinizi inceleyelim.
Dinleme: PreloadManagerListener ile analizleri getirme
Bir özelliği üretimde kullanıma sunmak istediğinizde, uygulama geliştirici olarak bu özelliğin arkasındaki analizleri de anlamak ve yakalamak istersiniz. Önceden yükleme stratejinizin gerçek dünya ortamında etkili olduğundan nasıl emin olabilirsiniz? Bu soruyu yanıtlamak için başarı oranları, hatalar ve performansla ilgili veriler gerekir. Bu verileri toplamak için kullanılan başlıca mekanizma PreloadManagerListener arayüzüdür.
PreloadManagerListener, önceden yükleme süreci ve durumu hakkında önemli bilgiler sunan iki temel geri çağırma sağlar.
- onCompleted(MediaItem mediaItem): Bu geri çağırma, TargetPreloadStatusControl'ünüzde tanımlandığı şekilde bir önceden yükleme isteği başarıyla tamamlandığında çağrılır.
- onError(PreloadException error): Bu geri çağırma, hata ayıklama ve izleme için yararlı olabilir. Ön yükleme başarısız olduğunda çağrılır ve ilişkili istisnayı sağlar.
Aşağıdaki örnek kodda gösterildiği gibi, tek bir yöntem çağrısıyla dinleyici kaydedebilirsiniz:
val preloadManagerListener = object : PreloadManagerListener { override fun onCompleted(mediaItem: MediaItem) { // Log success for analytics. Log.d("PreloadAnalytics", "Preload completed for $mediaItem") } override fun onError( preloadError: PreloadException) { // Log the specific error for debugging and monitoring. Log.e("PreloadAnalytics", "Preload error ", preloadError) } } preloadManager.addListener(preloadManagerListener)
Dinleyiciden analizler elde etme
Bu işleyici geri çağırmaları, analiz ardışık düzeninize kancalanabilir. Bu etkinlikleri analiz motorunuza yönlendirerek aşağıdaki gibi önemli soruları yanıtlayabilirsiniz:
- Ön yükleme başarı oranımız nedir? (onCompleted etkinliklerinin toplam önceden yükleme denemelerine oranı)
- Hangi CDN'ler veya video biçimleri en yüksek hata oranlarına sahip? (onError'daki istisnalar ayrıştırılarak)
- Ön yükleme hata oranımız nedir? (onError etkinliklerinin toplam önceden yükleme denemelerine oranı)
Bu veriler, ön yükleme stratejiniz hakkında nicel geri bildirim sağlayarak A/B testi yapmanıza ve kullanıcı deneyiminizde veriye dayalı iyileştirmeler yapmanıza olanak tanır. Bu veriler, önceden yükleme sürelerinizi ve önceden yüklemek istediğiniz video sayısını akıllıca ayarlamanıza ve ayırdığınız arabellekleri belirlemenize yardımcı olabilir.
Hata ayıklamanın ötesinde: onError'u kullanarak kullanıcı arayüzünde kontrollü geri dönüş
Önceden yükleme başarısız olduğunda kullanıcının yakında arabelleğe alma sorunu yaşayacağı anlaşılır. onError geri çağırma işlevi, tepkisel olarak yanıt vermenize olanak tanır. Hatayı yalnızca günlüğe kaydetmek yerine kullanıcı arayüzünü uyarlayabilirsiniz. Örneğin, sonraki video önceden yüklenemezse uygulamanız, sonraki kaydırma için otomatik oynatmayı devre dışı bırakabilir ve oynatmanın başlatılması için kullanıcının dokunmasını gerektirebilir.
Ayrıca, PreloadException türünü inceleyerek daha akıllı bir yeniden deneme stratejisi tanımlayabilirsiniz. Bir uygulama, hata mesajına veya HTTP durum koduna göre başarısız olan bir kaynağı yöneticiden hemen kaldırmayı seçebilir. Yükleme sorunlarının kullanıcı deneyimine yansımaması için öğenin kullanıcı arayüzü akışından kaldırılması gerekir. Hataları daha ayrıntılı bir şekilde incelemek için HttpDataSourceException gibi PreloadException'dan daha ayrıntılı veriler de alabilirsiniz. ExoPlayer sorunlarını giderme hakkında daha fazla bilgi edinin.
Yardımcı sistemi: Bileşenlerin ExoPlayer ile paylaşılması neden gereklidir?
DefaultPreloadManager ve ExoPlayer birlikte çalışacak şekilde tasarlanmıştır. Kararlılık ve verimlilik için çeşitli temel bileşenleri paylaşmaları gerekir. Ayrı ve koordine edilmemiş bileşenlerle çalışırlarsa önceden yüklenmiş parçaların doğru oynatıcıda çalınmasını sağlamamız gerektiğinden, iş parçacığı güvenliği ve oynatıcıdaki önceden yüklenmiş parçaların kullanılabilirliği etkilenebilir. Ayrı bileşenler, ağ bant genişliği ve bellek gibi sınırlı kaynaklar için de rekabet edebilir. Bu durum, performans düşüşüne yol açabilir. Yaşam döngüsünün önemli bir parçası da uygun şekilde bertaraf etmektir. Bertaraf etme için önerilen sıra önce PreloadManager'ı, ardından ExoPlayer'ı yayınlamaktır.
DefaultPreloadManager.Builder, bu paylaşımı kolaylaştırmak için tasarlanmıştır ve hem PreloadManager'ınızı hem de bağlı bir oynatıcı örneğini oluşturmak için API'lere sahiptir. BandwidthMeter, LoadControl, TrackSelector, Looper gibi bileşenlerin neden paylaşılması gerektiğini inceleyelim. Bu bileşenlerin ExoPlayer Playback ile nasıl etkileşime girdiğinin görsel temsilini inceleyin.
Paylaşılan bir BandwidthMeter ile bant genişliği çakışmalarını önleme
BandwidthMeter, geçmiş aktarım hızlarına göre kullanılabilir ağ bant genişliği tahmini sağlar. PreloadManager ve oynatıcı ayrı örnekler kullanıyorsa birbirlerinin ağ etkinliğinden haberdar olmaz. Bu durum, hata senaryolarına yol açabilir. Örneğin, bir kullanıcının video izlediği, ağ bağlantısının zayıfladığı ve önceden yüklenen MediaSource'un aynı anda gelecekteki bir video için agresif bir indirme işlemi başlattığı senaryoyu ele alalım. Önceden yüklenen MediaSource'un etkinliği, etkin oynatıcı için gereken bant genişliğini tüketerek mevcut videonun duraklamasına neden olur. Oynatma sırasında duraklama olması, kullanıcı deneyimi açısından önemli bir hatadır.
TrackSelector, tek bir BandwidthMeter paylaşarak ön yükleme veya oynatma sırasında mevcut ağ koşulları ve arabellek durumu göz önünde bulundurularak en yüksek kaliteli parçaları seçebilir. Ardından, etkin oynatma oturumunu korumak ve sorunsuz bir deneyim sağlamak için akıllı kararlar verebilir.
preloadManagerBuilder.setBandwidthMeter(customBandwidthMeter)
ExoPlayer'ın paylaşılan LoadControl, TrackSelector ve Renderer bileşenleriyle tutarlılık sağlama
- LoadControl: Bu bileşen, oynatmayı başlatmadan önce ne kadar veri arabelleğe alınacağı ve daha fazla veri yüklemeye ne zaman başlanacağı veya ne zaman son verileceği gibi arabelleğe alma politikasını belirler. LoadControl'ün paylaşılması, hem önceden yüklenmiş hem de etkin olarak oynatılan medyada oynatıcı ve PreloadManager'ın bellek tüketiminin tek ve koordineli bir arabelleğe alma stratejisiyle yönlendirilmesini sağlayarak kaynak çekişmesini önler. Tutarlılığı sağlamak için önceden yüklediğiniz öğelerin sayısına ve süresine göre arabellek boyutunu akıllıca ayarlamanız gerekir. Çakışma durumlarında oynatıcı, ekranda gösterilen mevcut öğenin oynatılmasına öncelik verir. Paylaşılan bir LoadControl ile önceden yükleme yöneticisi, önceden yükleme için ayrılan hedef arabellek baytları üst sınıra ulaşmadığı sürece önceden yüklemeye devam eder ve oynatma için yükleme tamamlanana kadar beklemez.
Not: Media3'ün (1.8) en yeni sürümünde LoadControl'ün paylaşılması, Allocator'ün PreloadManager ve oynatıcı ile doğru şekilde paylaşılmasını sağlar. Önceden yüklemeyi etkili bir şekilde kontrol etmek için LoadControl'ü kullanma özelliği, yakında yayınlanacak Media3 1.9 sürümünde kullanıma sunulacaktır.
preloadManagerBuilder.setLoadControl(customLoadControl)
- TrackSelector: Bu bileşen, hangi parçaların (örneğin, belirli bir çözünürlükteki video, belirli bir dildeki ses) yükleneceğini ve oynatılacağını seçmekten sorumludur. Paylaşım, önceden yükleme sırasında seçilen parçaların, oynatıcının kullanacağı parçalarla aynı olmasını sağlar. Bu sayede, 480p video parçasının önceden yüklenip oynatma sırasında hemen atıldığı ve 720p parçasının getirildiği gereksiz senaryo önlenir.<br /> Önceden yükleme yöneticisi, TrackSelector'ın aynı örneğini oynatıcıyla paylaşmamalıdır. Bunun yerine, aynı uygulamaya ait farklı bir TrackSelector örneği kullanmalıdırlar. Bu nedenle, DefaultPreloadManager.Builder'da TrackSelector yerine TrackSelectorFactory'yi ayarladık.
preloadManagerBuilder.setTrackSelectorFactory(customTrackSelectorFactory)
- Oluşturucu: Bu bileşen, tam oluşturucular oluşturmadan oynatıcının özelliklerini anlamaktan sorumludur. Bu planı kontrol ederek son oynatıcının hangi video, ses ve metin biçimlerini destekleyeceğini belirler. Bu sayede yalnızca uyumlu medya parçası akıllıca seçilip indirilir ve oynatıcının oynatamayacağı içeriklerde bant genişliği israfı önlenir.
preloadManagerBuilder.setRenderersFactory(customRenderersFactory)
Diğer Exoplayer bileşenleri hakkında bilgi edinin.
Altın kural: Hepsine hükmedecek ortak bir Oynatma Döngüsü
Bir ExoPlayer örneğine erişilebilecek iş parçacığı, oynatıcı oluşturulurken bir Looper iletilerek açıkça belirtilebilir. Oyuncuya erişilmesi gereken iş parçacığının döngücüsü, Player.getApplicationLooper kullanılarak sorgulanabilir. Oynatıcı ve PreloadManager arasında paylaşılan bir döngücü koruyarak, bu paylaşılan medya nesneleri üzerindeki tüm işlemlerin tek bir iş parçacığının mesaj kuyruğuna serileştirilmesi sağlanır. Bu, eşzamanlılık hatalarını azaltabilir.
PreloadManager ile yüklenecek veya önceden yüklenecek medya kaynaklarına sahip oynatıcı arasındaki tüm etkileşimler aynı oynatma iş parçacığında gerçekleşmelidir. İş parçacığı güvenliği için Looper'ın paylaşılması gerekir. Bu nedenle, PlaybackLooper, PreloadManager ve oynatıcı arasında paylaşılmalıdır.
PreloadManager, arka planda durum bilgisi içeren bir MediaSource nesnesi hazırlar. Kullanıcı arayüzü kodunuz player.setMediaSource(mediaSource) işlevini çağırdığında, bu karmaşık ve durum bilgisi içeren nesneyi önceden yüklenen MediaSource'tan oynatıcıya aktarıyorsunuz. Bu senaryoda, PreloadMediaSource'un tamamı yöneticiden oynatıcıya taşınır. Tüm bu etkileşimler ve devirler aynı PlaybackLooper üzerinde gerçekleşmelidir.
PreloadManager ve ExoPlayer farklı iş parçacıklarında çalışıyorsa yarış durumu oluşabilir. PreloadManager'ın iş parçacığı, oynatıcının iş parçacığı tam olarak okumaya çalışırken MediaSource'un dahili durumunu (ör.arabelleğe yeni veriler yazma) değiştiriyor olabilir. Bu durum, tahmin edilemeyen davranışlara ve hata ayıklaması zor olan IllegalStateException'a yol açar.
preloadManagerBuilder.setPreloadLooper(playbackLooper)
Kurulum sırasında yukarıdaki tüm bileşenleri ExoPlayer ve DefaultPreloadManager arasında nasıl paylaşabileceğinize bakalım.
val preloadManagerBuilder = DefaultPreloadManager.Builder(context, targetPreloadStatusControl) // Optional - Share components between ExoPlayer and DefaultPreloadManager preloadManagerBuilder .setBandwidthMeter(customBandwidthMeter) .setLoadControl(customLoadControl) .setMediaSourceFactory(customMediaSourceFactory) .setTrackSelectorFactory(customTrackSelectorFactory) .setRenderersFactory(customRenderersFactory) .setPreloadLooper(playbackLooper) val preloadManager = val preloadManagerBuilder.build()
İpucu: ExoPlayer'da DefaultLoadControl gibi varsayılan bileşenleri kullanıyorsanız bunları DefaultPreloadManager ile açıkça paylaşmanız gerekmez. ExoPlayer örneğinizi DefaultPreloadManager.Builder'ın buildExoPlayer aracılığıyla oluşturduğunuzda, varsayılan yapılandırmalarla varsayılan uygulamaları kullanıyorsanız bu bileşenler birbirleriyle otomatik olarak referanslanır. Ancak özel bileşenler veya özel yapılandırmalar kullanıyorsanız yukarıdaki API'ler aracılığıyla DefaultPreloadManager'ı bunlar hakkında açıkça bilgilendirmeniz gerekir.
Üretime hazır önceden yükleme: Kayar pencere kalıbı
Dinamik feed'lerde kullanıcılar neredeyse sonsuz miktarda içeriğe göz atabilir. DefaultPreloadManager'a sürekli olarak karşılık gelen bir kaldırma stratejisi olmadan video eklerseniz kaçınılmaz olarak OutOfMemoryError'a neden olursunuz. Önceden yüklenen her MediaSource, bellek arabelleklerini ayıran bir SampleQueue tutar. Bu tür nesneler biriktikçe uygulamanın yığın alanını tüketebilirler. Çözüm, muhtemelen bildiğiniz bir algoritmadır: kayan pencere. Kayar pencere modeli, bellekte kullanıcının feed'deki mevcut konumuyla mantıksal olarak bitişik olan küçük ve yönetilebilir bir öğe grubu tutar. Kullanıcı kaydırdıkça yönetilen öğelerin bu "penceresi" de kaydırılır. Böylece, görünür hale gelen yeni öğeler eklenir ve artık uzakta olan öğeler kaldırılır.
Kayan pencere desenini uygulama
PreloadManager'ın yerleşik bir setWindowSize() yöntemi sağlamadığını anlamak önemlidir. Kayar pencere, geliştirici olarak sizin temel add() ve remove() yöntemlerini kullanarak uygulamanız gereken bir tasarım kalıbıdır. Uygulama mantığınız, kaydırma veya sayfa değişikliği gibi kullanıcı arayüzü etkinliklerini bu API çağrılarına bağlamalıdır. Bu konuda kod referansı istiyorsanız socialite örneğinde bu kayan pencere kalıbı uygulanmıştır. Bu örnekte, kayan pencereyi taklit eden bir PreloadManagerWrapper da yer alır.
Öğe, kullanıcının izleme etkinliğinde yakında görünmeyecekse preloadManager.remove(mediaItem) işlevini eklemeyi unutmayın. Kullanıcıya artık yakın olmayan öğelerin kaldırılmaması, önceden yükleme uygulamalarındaki bellek sorunlarının temel nedenidir. remove() çağrısı, uygulamanızın bellek kullanımını sınırlı ve kararlı tutmanıza yardımcı olan kaynakların serbest bırakılmasını sağlar.
TargetPreloadStatusControl ile kategorize edilmiş bir önceden yükleme stratejisine ince ayar yapma
Önceden yüklenecek öğeleri (penceremizdeki öğeler) tanımladığımıza göre, her öğe için ne kadar önceden yükleme yapılacağına dair iyi tanımlanmış bir strateji uygulayabiliriz. 1. Bölüm'de TargetPreloadStatusControl kurulumuyla bu ayrıntı düzeyinin nasıl elde edileceğini zaten görmüştük.
Hatırlatmak gerekirse +/- 1 konumundaki bir öğenin, +/- 4 konumundaki bir öğeye göre oynatılma olasılığı daha yüksek olabilir. Kullanıcının bir sonraki görüntüleme olasılığı en yüksek olan öğelere daha fazla kaynak (ağ, CPU, bellek) ayırabilirsiniz. Bu, yakınlığa dayalı bir "ön yükleme" stratejisi oluşturur. Bu strateji, anında oynatmayı verimli kaynak kullanımıyla dengelemenin anahtarıdır.
Önceden yükleme süresi stratejinize karar vermek için önceki bölümlerde bahsedildiği gibi PreloadManagerListener aracılığıyla analiz verilerini kullanabilirsiniz.
Sonuç ve sonraki adımlar
Artık Media3'ün DefaultPreloadManager'ını kullanarak hızlı, kararlı ve kaynak açısından verimli medya feed'leri oluşturmak için gereken ileri düzey bilgilere sahipsiniz.
Temel çıkarımları özetleyelim:
- Analytics'ten edinilen bilgileri toplamak ve hataların etkili bir şekilde yönetilmesini sağlamak için PreloadManagerListener'ı kullanın.
- Önemli bileşenlerin paylaşılmasını sağlamak için hem yönetici hem de oynatıcı örneklerinizi oluştururken her zaman tek bir DefaultPreloadManager.Builder kullanın.
- OutOfMemoryError'u önlemek için add() ve remove() çağrılarını etkin bir şekilde yöneterek kayan pencere desenini uygulayın.
- Performans ve kaynak tüketimini dengeleyen akıllı ve katmanlı bir ön yükleme stratejisi oluşturmak için TargetPreloadStatusControl'ü kullanın.
3. Bölümde bir sonraki konu: Önceden yüklenmiş medya ile önbelleğe alma
Verilerin belleğe önceden yüklenmesi anında performans avantajı sağlar ancak bu durumun dezavantajları olabilir. Uygulama kapatıldığında veya önceden yüklenmiş medya yöneticiden kaldırıldığında veriler silinir. Daha kalıcı bir optimizasyon düzeyi elde etmek için önceden yüklemeyi disk önbelleğe alma ile birleştirebiliriz. Bu özellik aktif olarak geliştirilmektedir ve birkaç ay içinde kullanıma sunulacaktır.
Paylaşmak istediğiniz bir geri bildiriminiz var mı? Görüşlerinizi öğrenmekten memnuniyet duyarız.
Bizi takip etmeye devam edin ve video oynatma hızınızı artırın. 🚀
Okumaya devam edin
-
Ürün Haberleri
Günümüzün medya odaklı uygulamalarında, sorunsuz ve kesintisiz bir oynatma deneyimi sunmak, keyifli bir kullanıcı deneyimi için çok önemlidir. Kullanıcılar videolarının anında başlamasını ve sorunsuz bir şekilde oynatılmasını bekler.
Mayuri Khinvasara Khabya • Okuma süresi: 8 dk.
-
Ürün Haberleri
Android Emulator ile çeşitli cihaz etkileşimlerini test etmek artık her zamankinden daha kolay.
Steven Jenkins • Okuma süresi: 2 dakika
-
Ürün Haberleri
Her geliştiricinin yapay zeka iş akışı ve ihtiyaçları benzersizdir. Bu nedenle, yapay zekanın geliştirme sürecinize nasıl yardımcı olacağını seçebilmeniz önemlidir. Ocak ayında, Android Studio'daki yapay zeka işlevlerine güç katmak için yerel veya uzak bir yapay zeka modeli seçme özelliğini kullanıma sunduk.
Matthew Warner • Okuma süresi: 2 dakika
Gelişmelerden haberdar olun
Android geliştirmeyle ilgili en son analizleri her hafta gelen kutunuza alın.