ExoPlayer, medyayı çevrimdışı oynatma için indirme işlevi sunar. Çoğu kullanım alanında, uygulamanız arka planda olsa bile indirme işlemlerinin devam etmesi istenir. Bu kullanım alanlarında uygulamanız DownloadService sınıfının alt sınıfı olmalı ve indirmeleri eklemek, kaldırmak ve kontrol etmek için hizmete komut göndermelidir. Aşağıdaki şemada, ilgili ana sınıflar gösterilmektedir.
DownloadService:DownloadManageröğesini sarmalar ve komutları bu öğeye yönlendirir. Bu hizmet, uygulama arka planda olsa bileDownloadManager'nın çalışmaya devam etmesine olanak tanır.DownloadManager: Birden fazla indirme işlemini yönetir, durumlarınıDownloadIndexüzerinden (veyaDownloadIndex'ye) yükler (ve depolar), indirme işlemlerini ağ bağlantısı gibi gereksinimlere göre başlatır ve durdurur. İçeriği indirmek için yönetici genellikleHttpDataSourcekonumundan indirilen verileri okur veCachekonumuna yazar.DownloadIndex: İndirmelerin durumlarını kalıcı hale getirir.
DownloadService oluşturma
DownloadService oluşturmak için alt sınıfını oluşturun ve soyut yöntemlerini uygulayın:
getDownloadManager(): KullanılacakDownloadManagerdeğerini döndürür.getScheduler(): Bekleyen indirme işlemlerinin ilerlemesi için gereken koşullar karşılandığında hizmeti yeniden başlatabilen isteğe bağlı birSchedulerdöndürür. ExoPlayer aşağıdaki uygulamaları sağlar:- JobScheduler'ı (minimum API düzeyi 21) kullanan
PlatformSchedulerUygulama izni şartları için PlatformScheduler javadocs'a bakın. WorkManagerScheduler, WorkManager'ı kullanır.
- JobScheduler'ı (minimum API düzeyi 21) kullanan
getForegroundNotification(): Hizmet ön planda çalışırken gösterilecek bir bildirim döndürür. Varsayılan stilde bildirim oluşturmak içinDownloadNotificationHelper.buildProgressNotificationkullanabilirsiniz.
Son olarak, hizmeti AndroidManifest.xml dosyanızda 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 öğelerine bakın.
DownloadManager oluşturma
Aşağıdaki kod snippet'inde, DownloadManager öğesinin nasıl örneklendirileceği gösterilmektedir. Bu öğe, DownloadService öğenizdeki getDownloadManager() tarafından döndürülebilir:
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 DownloadRequest oluşturup DownloadService adresinize gönderin. Uyarlanabilir akışlar için DownloadHelper kullanarak DownloadRequest oluşturun. 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 ayrıca bazı isteğe bağlı ayarlayıcılara da sahiptir. Örneğin, setKeySetId ve setData, sırasıyla uygulamanın indirmeyle ilişkilendirmek istediği DRM ve özel verileri ayarlamak için kullanılabilir. İçerik türünün contentUri öğesinden anlaşılamadığı durumlarda ipucu olarak setMimeType kullanılarak içeriğin MIME türü de belirtilebilir.
Oluşturulan istek, indirme işlemini eklemek için DownloadService adresine 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ı, foreground parametresi ise hizmetin ön planda başlatılıp başlatılmayacağını kontrol eder. Uygulamanız zaten ön plandaysa foreground parametresi normalde false olarak ayarlanmalıdır. Çünkü DownloadService, yapması gereken bir iş olduğunu belirlerse kendisini ön plana çıkarır.
İndirilenler kaldırılıyor
İndirme, DownloadService hizmetine bir kaldırma komutu gönderilerek kaldırılabilir. Burada contentId, kaldırılacak indirmeyi tanımlar:
Kotlin
DownloadService.sendRemoveDownload( context, MyDownloadService::class.java, contentId, /* foreground= */ false, )
Java
DownloadService.sendRemoveDownload( context, MyDownloadService.class, contentId, /* foreground= */ false);
İndirilen tüm verileri DownloadService.sendRemoveAllDownloads ile de kaldırabilirsiniz.
İndirme işlemlerini başlatma ve durdurma
İndirme işleminin devam edebilmesi için dört koşulun karşılanması gerekir:
- İndirme işleminin durdurulma nedeni yok.
- İndirmeler duraklatılmamış olmalıdır.
- İndirme işleminin devam etmesi için gereken koşullar karşılanmalıdır. Gereksinimler, izin verilen ağ türleriyle ilgili kısıtlamaları ve cihazın boşta mı olması yoksa şarj cihazına mı bağlı olması gerektiğini belirtebilir.
- Maksimum paralel indirme sayısı aşılmamalıdır.
Bu koşulların tümü, DownloadService cihazınıza komut gönderilerek kontrol edilebilir.
İndirme durdurma nedenlerini ayarlama ve temizleme
Bir veya tüm indirme işlemlerinin durdurulması için neden belirleyebilirsiniz:
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, indirmenin durdurulmadığı anlamına gelen özel bir değerdir). İndirmelerin durdurulması için birden fazla nedeni olan uygulamalar, her indirme işleminin neden durdurulduğunu takip etmek için farklı değerler kullanabilir. Tüm indirmeler için durdurma nedenini ayarlama ve temizleme işlemi, tek bir indirme için durdurma nedenini ayarlama ve temizleme işlemiyle aynı şekilde çalışır. Ancak contentId, null olarak ayarlanmalıdır.
Durdurma nedeni sıfır olmayan indirmeler Download.STATE_STOPPED durumunda olur. Durdurma nedenleri DownloadIndex içinde kalıcı olarak saklanır. Bu nedenle, uygulama işlemi sonlandırılıp daha sonra yeniden başlatılırsa durdurma nedenleri korunur.
Tüm indirme işlemlerini duraklatma ve devam ettirme
Tüm indirme işlemleri 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 indirmeler Download.STATE_QUEUED durumunda olur.
Durdurma nedenlerini ayarlamanın aksine, bu yaklaşımda durum değişiklikleri kalıcı olmaz. Bu yalnızca DownloadManager öğesinin çalışma zamanı durumunu etkiler.
İndirme işleminin devam etmesi için gerekenleri ayarlama
Requirements, indirme işleminin devam etmesi için karşılanması gereken kısıtlamaları belirtmek üzere kullanılabilir. Şartlar, DownloadManager oluşturulurken DownloadManager.setRequirements() çağrılarak ayarlanabilir. Bu işlem, yukarıdaki örnekte gösterilmiştir. Ayrıca DownloadService adresine komut gönderilerek dinamik olarak da değiştirilebilirler:
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);
Gereksinimler karşılanmadığı için indirme işlemi devam edemediğinde 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ılarak ayarlanabilir. Bu işlem normalde yukarıdaki örnekte olduğu gibi DownloadManager oluşturulurken yapılır.
Maksimum sayıda paralel indirme işlemi zaten devam ettiği için indirme işlemi devam edemediğinde Download.STATE_QUEUED durumunda olur.
İndirilenleri sorgulama
DownloadManager DownloadIndex, tamamlanan veya başarısız olanlar da dahil olmak üzere tüm indirmelerin durumu için sorgulanabilir. DownloadIndex
numaralı telefonu arayarak DownloadManager.getDownloadIndex() kodunu alabilirsiniz. Daha sonra DownloadIndex.getDownloads() çağrılarak tüm indirmeler üzerinde yineleme yapan bir imleç elde edilebilir. Alternatif olarak, DownloadIndex.getDownload() işlevi çağrılarak tek bir indirmenin durumu sorgulanabilir.
DownloadManager ayrıca yalnızca mevcut (yani tamamlanmamış veya başarısız olmuş) indirmelerin durumunu döndüren DownloadManager.getCurrentDownloads() işlevini de sağlar. Bu yöntem, bildirimleri ve mevcut indirmelerin ilerleme durumunu gösteren 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 bilgilendirilmek için DownloadManager öğesine 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 bölümüne bakın.
İndirilen içeriği oynatma
İndirilen içerikleri oynatmak, ağ üzerinden değil, indirme işleminden Cache veri okunması dışında online içerikleri oynatmaya benzer.
İndirilen içeriği oynatmak için indirme işleminde kullanılan Cache örneğiyle aynı CacheDataSource.Factory öğesini oluşturun ve oynatıcıyı oluştururken DefaultMediaSourceFactory öğesine yerleştirin:
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, indirilmeyen içerikleri oynatmak için de kullanılacaksa oynatma sırasında bu içeriklerin 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çeriklere oynatma için erişebilir. İndirilen içeriği oynatmak için ilgili MediaItem öğesini oyuncuya iletmeniz yeterlidir. MediaItem, Download.request.toMediaItem kullanılarak Download üzerinden veya DownloadRequest.toMediaItem kullanılarak doğrudan DownloadRequest üzerinden alınabilir.
MediaSource yapılandırması
Önceki örnekte, indirme önbelleği tüm MediaItem'ların oynatılması için kullanılabilir hale getiriliyor. İndirme önbelleğini, doğrudan oynatıcıya aktarılabilen 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) normalde birden fazla medya parçası içerir. Genellikle farklı kalitelerde (ör. SD, HD ve 4K video parçaları) aynı içeriği içeren birden fazla parça bulunur. Aynı türde olup farklı içerikler barındıran birden fazla parça da olabilir (ör. farklı dillerde birden fazla ses parçası).
Akış oynatmalarda, hangi parçaların oynatılacağını seçmek için parça seçici kullanılabilir. Benzer şekilde, indirme işleminde hangi parçaların indirileceğini seçmek için DownloadHelper kullanılabilir. DownloadHelper
tipik kullanımı aşağıdaki adımlardan oluşur:
DownloadHelper.Factoryörneğini kullanarakDownloadHelperoluşturun. Yardımcıyı hazırlayın ve geri aramayı bekleyin.- İsteğe bağlı olarak,
getMappedTrackInfovegetTrackSelectionssimgelerini kullanarak varsayılan olarak seçilen parçaları inceleyin veclearTrackSelections,replaceTrackSelectionsveaddTrackSelectionsimgelerini kullanarak düzenlemeler yapın. DownloadRequestişlevini çağırarak seçili parçalar içingetDownloadRequestoluşturun. İstek, yukarıda açıklandığı gibi indirme işlemini eklemek içinDownloadService'nize iletilebilir.release()kullanarak yardımcıyı serbest bırakın.
Kotlin
val downloadHelper = DownloadHelper.Factory() .setRenderersFactory(DefaultRenderersFactory(context)) .setDataSourceFactory(dataSourceFactory) .create(MediaItem.fromUri(contentUri)) downloadHelper.prepare(callback)
Java
DownloadHelper downloadHelper = new DownloadHelper.Factory() .setRenderersFactory(new DefaultRenderersFactory(context)) .setDataSourceFactory(dataSourceFactory) .create(MediaItem.fromUri(contentUri)); downloadHelper.prepare(callback);
İndirilen uyarlanabilir içeriğin oynatılması için yukarıda açıklandığı gibi oynatıcının yapılandırılması ve ilgili MediaItem'nın iletilmesi gerekir.
MediaItem oluşturulurken MediaItem.localConfiguration.streamKeys, oynatıcının yalnızca indirilen parçaların alt kümesini çalmaya çalışması için DownloadRequest'daki değerlerle eşleşecek şekilde ayarlanmalıdır. Download.request.toMediaItem ve DownloadRequest.toMediaItem kullanarak MediaItem oluşturduğunuzda bu işlem sizin için otomatik olarak yapılır.