ExoPlayer, çevrimdışı oynatma için medya indirme işlevi sağlar. Çoğu kullanım alanında, uygulamanız arka plandayken bile indirmelerin devam etmesi istenir. Bu kullanım alanlarında uygulamanız DownloadService
alt sınıfını olmalı ve indirmeleri eklemek, kaldırmak ve kontrol etmek için hizmete komutlar göndermelidir. Aşağıdaki şemada, dahil olan ana sınıflar gösterilmektedir.
DownloadService
: BirDownloadManager
'ı sarmalayarak komutları ona iletir. Bu hizmet, uygulama arka plandayken bileDownloadManager
'ün çalışmaya devam etmesine olanak tanır.DownloadManager
: Birden fazla indirme işlemini yönetir, indirme işlemlerinin durumlarını birDownloadIndex
'dan (veyaDownloadIndex
'a) yükler (ve depolar), indirme işlemlerini ağ bağlantısı gibi koşullara göre başlatır ve durdurur. Yönetici, içeriği indirmek için genellikleHttpDataSource
'ten indirilen verileri okuyupCache
'a yazar.DownloadIndex
: İndirmelerin durumlarını korur.
DownloadService oluşturma
Bir DownloadService
oluşturmak için sınıfını alt sınıfa alın ve soyut yöntemlerini uygulayın:
getDownloadManager()
: KullanılacakDownloadManager
değerini döndürür.getScheduler()
: Beklemedeki indirmelerin devam etmesi için gereken şartlar karşılandığında hizmeti yeniden başlatabilecek isteğe bağlı birScheduler
döndürür. ExoPlayer aşağıdaki uygulamaları sağlar:PlatformScheduler
, JobScheduler'ı kullanır (Minimum API düzeyi 21'dir). Uygulama izni şartları için PlatformScheduler javadoc'larına bakın.WorkManagerScheduler
, WorkManager'ı kullanır.
getForegroundNotification()
: Hizmet ön planda çalışırken görüntülenecek bir bildirim döndürür. Varsayılan stilde bildirim oluşturmak içinDownloadNotificationHelper.buildProgressNotification
kullanabilirsiniz.
Son olarak, AndroidManifest.xml
dosyanızda hizmeti tanımlayın:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>
<application>
<service android:name="com.myapp.MyDownloadService"
android:exported="false"
android:foregroundServiceType="dataSync">
<!-- This is needed for Scheduler -->
<intent-filter>
<action android:name="androidx.media3.exoplayer.downloadService.action.RESTART"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
</application>
Somut bir örnek için ExoPlayer demo uygulamasındaki DemoDownloadService
ve AndroidManifest.xml
sürümlerine göz atın.
İndirme Yöneticisi Oluşturma
Aşağıdaki kod snippet'inde, DownloadService
içinde getDownloadManager()
tarafından döndürülebilecek bir DownloadManager
öğesinin nasıl oluşturulacağı gösterilmektedir:
Kotlin
// Note: This should be a singleton in your app. val databaseProvider = StandaloneDatabaseProvider(context) // A download cache should not evict media, so should use a NoopCacheEvictor. val downloadCache = SimpleCache(downloadDirectory, NoOpCacheEvictor(), databaseProvider) // Create a factory for reading the data from the network. val dataSourceFactory = DefaultHttpDataSource.Factory() // Choose an executor for downloading data. Using Runnable::run will cause each download task to // download data on its own thread. Passing an executor that uses multiple threads will speed up // download tasks that can be split into smaller parts for parallel execution. Applications that // already have an executor for background downloads may wish to reuse their existing executor. val downloadExecutor = Executor(Runnable::run) // Create the download manager. val downloadManager = DownloadManager(context, databaseProvider, downloadCache, dataSourceFactory, downloadExecutor) // Optionally, properties can be assigned to configure the download manager. downloadManager.requirements = requirements downloadManager.maxParallelDownloads = 3
Java
// Note: This should be a singleton in your app. databaseProvider = new StandaloneDatabaseProvider(context); // A download cache should not evict media, so should use a NoopCacheEvictor. downloadCache = new SimpleCache(downloadDirectory, new NoOpCacheEvictor(), databaseProvider); // Create a factory for reading the data from the network. dataSourceFactory = new DefaultHttpDataSource.Factory(); // Choose an executor for downloading data. Using Runnable::run will cause each download task to // download data on its own thread. Passing an executor that uses multiple threads will speed up // download tasks that can be split into smaller parts for parallel execution. Applications that // already have an executor for background downloads may wish to reuse their existing executor. Executor downloadExecutor = Runnable::run; // Create the download manager. downloadManager = new DownloadManager( context, databaseProvider, downloadCache, dataSourceFactory, downloadExecutor); // Optionally, setters can be called to configure the download manager. downloadManager.setRequirements(requirements); downloadManager.setMaxParallelDownloads(3);
Somut bir örnek için demo uygulamasındaki DemoUtil
bölümüne bakın.
İndirme ekleme
İndirme eklemek için bir DownloadRequest
oluşturun ve DownloadService
'inize gönderin. Uyarlanabilir akışlarda DownloadRequest
oluşturulmasına yardımcı olmak için DownloadHelper
özelliğini kullanın. Aşağıdaki örnekte, indirme isteğinin nasıl oluşturulacağı gösterilmektedir:
Kotlin
val downloadRequest = DownloadRequest.Builder(contentId, contentUri).build()
Java
DownloadRequest downloadRequest = new DownloadRequest.Builder(contentId, contentUri).build();
Bu örnekte contentId
, içeriğin benzersiz tanımlayıcısıdır. Basit durumlarda contentUri
genellikle contentId
olarak kullanılabilir ancak uygulamalar, kullanım alanlarına en uygun kimlik şemasını kullanmakta serbesttir. DownloadRequest.Builder
'te bazı isteğe bağlı ayarlayıcılar da vardır. Örneğin, setKeySetId
ve setData
, DRM'yi ve uygulamanın indirme işlemiyle ilişkilendirmek istediği özel verileri sırasıyla ayarlamak için kullanılabilir. İçeriğin MIME türü, içerik türünün contentUri
'ten çıkarılamadığı durumlarda ipucu olarak setMimeType
kullanılarak da belirtilebilir.
Oluşturulan istek, indirme işlemini eklemek için DownloadService
'e gönderilebilir:
Kotlin
DownloadService.sendAddDownload( context, MyDownloadService::class.java, downloadRequest, /* foreground= */ false )
Java
DownloadService.sendAddDownload( context, MyDownloadService.class, downloadRequest, /* foreground= */ false);
Bu örnekte MyDownloadService
, uygulamanın DownloadService
alt sınıfıdır ve foreground
parametresi, hizmetin ön planda başlatılıp başlatılmayacağını kontrol eder. Uygulamanız zaten ön plandaysa DownloadService
, yapması gereken bir iş olduğunu belirlerse kendisini ön plana koyacağından foreground
parametresi normalde false
olarak ayarlanmalıdır.
İndirilenler kaldırılıyor
Bir indirme, DownloadService
adresine kaldırma komutu gönderilerek kaldırılabilir. Bu komutta contentId
, kaldırılacak indirme işlemini tanımlar:
Kotlin
DownloadService.sendRemoveDownload( context, MyDownloadService::class.java, contentId, /* foreground= */ false )
Java
DownloadService.sendRemoveDownload( context, MyDownloadService.class, contentId, /* foreground= */ false);
Ayrıca, indirilen tüm verileri DownloadService.sendRemoveAllDownloads
ile kaldırabilirsiniz.
İndirme işlemlerini başlatma ve durdurma
İndirme işlemi yalnızca dört koşul karşılanırsa devam eder:
- İndirme işleminin duraklatma nedeni yok.
- İndirmeler duraklatılmaz.
- Devam etmek için indirme koşulları karşılanır. Şartlar, izin verilen ağ türleriyle ilgili kısıtlamaların yanı sıra cihazın boşta mı yoksa bir şarj cihazına bağlı mı olması gerektiğini belirtebilir.
- Maksimum paralel indirme sayısı aşılmaz.
Bu koşulların tümü, DownloadService
cihazınıza komut göndererek kontrol edilebilir.
İndirme işleminin durdurulma nedenlerini ayarlama ve temizleme
Bir veya tüm indirme işlemlerinin durdurulmasına neden olan durumu ayarlayabilirsiniz:
Kotlin
// Set the stop reason for a single download. DownloadService.sendSetStopReason( context, MyDownloadService::class.java, contentId, stopReason, /* foreground= */ false ) // Clear the stop reason for a single download. DownloadService.sendSetStopReason( context, MyDownloadService::class.java, contentId, Download.STOP_REASON_NONE, /* foreground= */ false )
Java
// Set the stop reason for a single download. DownloadService.sendSetStopReason( context, MyDownloadService.class, contentId, stopReason, /* foreground= */ false); // Clear the stop reason for a single download. DownloadService.sendSetStopReason( context, MyDownloadService.class, contentId, Download.STOP_REASON_NONE, /* foreground= */ false);
stopReason
, sıfır olmayan herhangi bir değer olabilir (Download.STOP_REASON_NONE = 0
, indirme işleminin durdurulmadığı anlamına gelen özel bir değerdir). İndirmelerin durdurulmasının birden fazla nedeni olan uygulamalar, her indirmenin neden durdurulduğunu takip etmek için farklı değerler kullanabilir. Tüm indirme işlemlerinin durdurma nedenini ayarlama ve temizleme işlemi, tek bir indirme işleminin durdurma nedenini ayarlama ve temizleme işlemiyle aynı şekilde çalışır. Tek fark, contentId
parametresinin null
olarak ayarlanmasıdır.
Durdurma nedeni sıfır olmayan bir indirme Download.STATE_STOPPED
durumundadır. Durdurma nedenleri DownloadIndex
içinde kalır ve bu nedenle, uygulama işlemi sonlandırılıp daha sonra yeniden başlatılırsa saklanır.
Tüm indirmeler duraklatılıyor ve devam ettiriliyor
Tüm indirmeler aşağıdaki şekilde duraklatılabilir ve devam ettirilebilir:
Kotlin
// Pause all downloads. DownloadService.sendPauseDownloads( context, MyDownloadService::class.java, /* foreground= */ false ) // Resume all downloads. DownloadService.sendResumeDownloads( context, MyDownloadService::class.java, /* foreground= */ false )
Java
// Pause all downloads. DownloadService.sendPauseDownloads(context, MyDownloadService.class, /* foreground= */ false); // Resume all downloads. DownloadService.sendResumeDownloads(context, MyDownloadService.class, /* foreground= */ false);
Duraklatılan indirmelerin durumu Download.STATE_QUEUED
olur.
Durma nedenlerini ayarlama yönteminin aksine bu yaklaşımda durum değişiklikleri devam etmez. Yalnızca DownloadManager
öğesinin çalışma zamanı durumunu etkiler.
İndirmelerin devam etmesi için gereksinimleri ayarlama
Requirements
, indirme işleminin devam edebilmesi için karşılanması gereken kısıtlamaları belirtmek için kullanılabilir. Koşullar, yukarıdaki örnekte olduğu gibi DownloadManager
oluşturulurken DownloadManager.setRequirements()
çağırılarak ayarlanabilir. Ayrıca DownloadService
'ye komut göndererek dinamik olarak da değiştirilebilir:
Kotlin
// Set the download requirements. DownloadService.sendSetRequirements( context, MyDownloadService::class.java, requirements, /* foreground= */ false)
Java
// Set the download requirements. DownloadService.sendSetRequirements( context, MyDownloadService.class, requirements, /* foreground= */ false);
Gerekli koşullar karşılanmadığı için indirme işlemi devam edemiyorsa Download.STATE_QUEUED
durumunda olur. DownloadManager.getNotMetRequirements()
ile karşılanmayan koşulları sorgulayabilirsiniz.
Maksimum paralel indirme sayısını ayarlama
Maksimum paralel indirme sayısı, DownloadManager.setMaxParallelDownloads()
çağrısı yapılarak ayarlanabilir. Bu, normalde yukarıdaki örnekte olduğu gibi, DownloadManager
oluşturulurken yapılır.
Devam eden maksimum paralel indirme işlemi olduğu için indirme işlemi devam edemezse Download.STATE_QUEUED
durumunda olur.
İndirilenleri sorgulama
Bir DownloadManager
'ın DownloadIndex
özelliği, tamamlanan veya başarısız olanlar da dahil olmak üzere tüm indirme işlemlerinin durumu için sorgulanabilir. DownloadIndex
, DownloadManager.getDownloadIndex()
numarası arandığında elde edilebilir. Tüm indirmelerde iterasyon yapan bir imleç, daha sonra DownloadIndex.getDownloads()
çağrısı yapılarak elde edilebilir. Alternatif olarak, tek bir indirme işleminin durumu DownloadIndex.getDownload()
çağrısı yapılarak sorgulanabilir.
DownloadManager
, yalnızca mevcut (ör. tamamlanmamış veya başarısız) indirmelerin durumunu döndüren DownloadManager.getCurrentDownloads()
değerini de sağlar. Bu yöntem, mevcut indirme işlemlerinin ilerleme durumunu ve durumunu gösteren bildirimleri ve diğer kullanıcı arayüzü bileşenlerini güncellemek için kullanışlıdır.
İndirilenleri dinleme
Mevcut indirmelerin durumu değiştiğinde bilgi almak için DownloadManager
uygulamasına bir dinleyici ekleyebilirsiniz:
Kotlin
downloadManager.addListener( object : DownloadManager.Listener { // Override methods of interest here. } )
Java
downloadManager.addListener( new DownloadManager.Listener() { // Override methods of interest here. });
Somut bir örnek için demo uygulamanın DownloadTracker
sınıfındaki DownloadManagerListener
öğesine bakın.
İndirilen içeriği oynatma
İndirilen içeriğin oynatılması, internetteki içeriğin oynatılmasına benzer. Tek fark, verilerin ağ üzerinden değil, indirilen içerikten Cache
okunmasıdır.
İndirilen içeriği oynatmak için indirme için kullanılan Cache
örneğini kullanarak bir CacheDataSource.Factory
oluşturun ve oynatıcıyı oluştururken bu örneği DefaultMediaSourceFactory
içine ekleyin:
Kotlin
// Create a read-only cache data source factory using the download cache. val cacheDataSourceFactory: DataSource.Factory = CacheDataSource.Factory() .setCache(downloadCache) .setUpstreamDataSourceFactory(httpDataSourceFactory) .setCacheWriteDataSinkFactory(null) // Disable writing. val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory) ) .build()
Java
// Create a read-only cache data source factory using the download cache. DataSource.Factory cacheDataSourceFactory = new CacheDataSource.Factory() .setCache(downloadCache) .setUpstreamDataSourceFactory(httpDataSourceFactory) .setCacheWriteDataSinkFactory(null); // Disable writing. ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory)) .build();
Aynı oynatıcı örneği, indirilmemiş içerikleri oynatmak için de kullanılacaksa oynatma sırasında bu içeriğin de indirilmesini önlemek için CacheDataSource.Factory
salt okunur olarak yapılandırılmalıdır.
Oynatıcı CacheDataSource.Factory
ile yapılandırıldıktan sonra, indirilen içeriğe oynatma için erişebilir. Bu durumda, indirilen bir içeriği oynatmak, ilgili MediaItem
öğesini oynatıcıya iletmek kadar basittir. MediaItem
, Download.request.toMediaItem
kullanılarak bir Download
'dan veya DownloadRequest.toMediaItem
kullanılarak doğrudan bir DownloadRequest
'den elde edilebilir.
MediaSource yapılandırması
Önceki örnekte, indirme önbelleği tüm MediaItem
'lerin oynatılması için kullanılabilir hale getirilmiştir. İndirme önbelleğini, doğrudan oynatıcıya iletilebilecek tek tek MediaSource
örnekleri için de kullanılabilir hale getirebilirsiniz:
Kotlin
val mediaSource = ProgressiveMediaSource.Factory(cacheDataSourceFactory) .createMediaSource(MediaItem.fromUri(contentUri)) player.setMediaSource(mediaSource) player.prepare()
Java
ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(cacheDataSourceFactory) .createMediaSource(MediaItem.fromUri(contentUri)); player.setMediaSource(mediaSource); player.prepare();
Uyarlanabilir akışları indirme ve oynatma
Uyarlanabilir akışlar (ör. DASH, SmoothStreaming ve HLS) genellikle birden fazla medya parçası içerir. Genellikle aynı içeriği farklı kalitede (ör. SD, HD ve 4K video parçaları) barındıran birden fazla parça bulunur. Aynı türde farklı içerikler içeren birden fazla parça da olabilir (ör. farklı dillerde birden fazla ses parçası).
Akış oynatmalarında, hangi parçaların çalınacağını seçmek için bir parça seçici kullanılabilir. Benzer şekilde, indirme işlemi sırasında hangi parçaların indirileceğini seçmek için bir DownloadHelper
kullanılabilir. DownloadHelper
tipik kullanımı aşağıdaki adımları izler:
DownloadHelper.forMediaItem
yöntemlerinden birini kullanarak birDownloadHelper
oluşturun. Yardımcıyı hazırlayın ve geri aramayı bekleyin.Kotlin
val downloadHelper = DownloadHelper.forMediaItem( context, MediaItem.fromUri(contentUri), DefaultRenderersFactory(context), dataSourceFactory ) downloadHelper.prepare(callback)
Java
DownloadHelper downloadHelper = DownloadHelper.forMediaItem( context, MediaItem.fromUri(contentUri), new DefaultRenderersFactory(context), dataSourceFactory); downloadHelper.prepare(callback);
- İsteğe bağlı olarak,
getMappedTrackInfo
vegetTrackSelections
tuşlarını kullanarak varsayılan olarak seçili parçaları inceleyebilir veclearTrackSelections
,replaceTrackSelections
veaddTrackSelection
tuşlarını kullanarak düzenlemeler yapabilirsiniz. getDownloadRequest
işlevini çağırarak seçili parçalar için birDownloadRequest
oluşturun. Yukarıda açıklandığı şekilde, indirme işlemini eklemek için istekDownloadService
'inize iletilebilir.release()
simgesini kullanarak yardımcıyı serbest bırakın.
İndirilen uyarlanabilir içeriğin oynatılabilmesi için oynatıcının yapılandırılması ve yukarıda açıklandığı gibi ilgili MediaItem
öğesinin iletilmesi gerekir.
MediaItem
oluşturulurken MediaItem.localConfiguration.streamKeys
, oynatıcının yalnızca indirilen parça alt kümesini çalmaya çalışması için DownloadRequest
'dekilerle eşleşecek şekilde ayarlanmalıdır. MediaItem
oluşturmak için Download.request.toMediaItem
ve DownloadRequest.toMediaItem
'ü kullandığınızda bu işlem sizin için yapılır.