ExoPlayer, çevrimdışı oynatma için medya indirme işlevi sağlar. Çoğu kullanım durumunda, uygulamanız arka plandayken bile indirme işlemlerinin devam etmesi istenir. Bu kullanım alanlarında uygulamanız DownloadService
alt sınıfını oluşturmalı ve indirmeleri eklemek, kaldırmak ve kontrol etmek için hizmete komutlar göndermelidir. Aşağıdaki şemada, programa dahil olan başlıca sınıflar gösterilmektedir.
DownloadService
: BirDownloadManager
öğesini sarmalar ve komutları buna yönlendirir. Bu hizmet, uygulama arka plandayken bileDownloadManager
hizmetinin çalışmaya devam etmesini sağlar.DownloadManager
: Birden çok indirme işlemini, durumlarınıDownloadIndex
ile yükleme (ve depolama) ve indirme işlemlerini ağ bağlantısı gibi gerekliliklere göre başlatıp durdurma işlemlerini yönetir. Yönetici, içeriği indirmek için genellikle birHttpDataSource
ağından indirilen verileri okur ve birCache
içine yazar.DownloadIndex
: İndirmelerin durumlarını korur.
İndirme Hizmeti Oluşturma
DownloadService
oluşturmak için alt sınıf oluşturun ve soyut yöntemlerini uygulayın:
getDownloadManager()
: KullanılacakDownloadManager
değerini döndürür.getScheduler()
: Bekleyen indirmelerin ilerlemesi için gerekli koşullar karşılandığında hizmeti yeniden başlatabilen isteğe bağlı birScheduler
döndürür. ExoPlayer aşağıdaki uygulamaları sağlar:- JobScheduler kullanan
PlatformScheduler
(Minimum API 21'dir). Uygulama izni gereksinimleri için PlatformScheduler Java dokümanlarına bakın. - WorkManager'ı kullanan
WorkManagerScheduler
.
- JobScheduler kullanan
getForegroundNotification()
: Hizmet ön planda çalışırken görüntülenecek bir bildirim döndürür. Varsayılan tarzda bir 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ında DemoDownloadService
ve AndroidManifest.xml
konularına bakın.
İndirme Yöneticisi oluşturma
Aşağıdaki kod snippet'i, DownloadService
içinde getDownloadManager()
tarafından döndürülebilecek bir DownloadManager
öğesinin nasıl örnekleneceğini gösterir:
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ında DemoUtil
adresine bakın.
İndirilen bir dosyayı ekleme
İndirme eklemek için bir DownloadRequest
oluşturup DownloadService
cihazınıza gönderin. Uyarlanabilir akışlarda DownloadRequest
oluşturulmasına yardımcı olmak için DownloadHelper
kullanın. Aşağıdaki örnekte, bir 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çerik için benzersiz bir tanımlayıcıdır. Basit durumlarda contentUri
genellikle contentId
olarak kullanılabilir ancak uygulamalar, kullanım alanlarına en uygun kimlik şemasını kullanabilir. DownloadRequest.Builder
öğesinde isteğe bağlı bazı
belirleyiciler de vardır. Örneğin, setKeySetId
ve setData
, uygulamanın indirmeyle ilişkilendirmek istediği DRM'yi ve özel verileri sırasıyla ayarlamak için kullanılabilir. İçeriğin MIME türü, içerik türünün contentUri
parametresinden çıkarılamadığı durumlar için ipucu olarak setMimeType
kullanılarak da belirtilebilir.
İstek oluşturulduktan sonra, indirilen öğenin eklenmesi için DownloadService
öğesine 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şin olduğunu belirlerse kendini ön plana koyar. Bu nedenle, foreground
parametresinin normalde false
olarak ayarlanması gerekir.
İndirilenler kaldırılıyor
İndirilen bir dosya DownloadService
öğesine kaldır komutu gönderilerek kaldırılabilir. Burada 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 DownloadService.sendRemoveAllDownloads
ile indirilen tüm verileri 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 bir durdurma nedeni yok.
- İndirme işlemleri duraklatılmaz.
- İndirme işleminin ilerleme durumu için gereksinimler karşılandı. Gereksinimler, cihazın boşta mı yoksa şarj cihazına bağlı mı olacağının yanı sıra izin verilen ağ türleriyle ilgili kısıtlamaları belirtebilir.
- Maksimum paralel indirme sayısı aşılmadı.
Bu koşulların tümü, DownloadService
cihazınıza komut gönderilerek kontrol edilebilir.
İndirmeyi durdurma nedenlerini ayarlama ve temizleme
İndirmelerden birinin veya tüm indirmelerin durdurulmasına neden olacak bir neden belirlemek mümkündür:
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 dışında herhangi bir değer olabilir (Download.STOP_REASON_NONE = 0
, indirme işleminin durdurulmadığı anlamına gelen özel bir değerdir). İndirme işlemlerini durdurmak için birden çok nedeni olan uygulamalar, her bir indirme işleminin neden durdurulduğunu izlemek için farklı değerler kullanabilir. Tüm indirmelerin durdurma nedenini ayarlamak ve temizlemek, tek bir indirmenin durdurma nedenini belirlemek ve temizlemekle aynı şekilde işler. Ancak contentId
, null
olarak ayarlanmalıdır.
Sıfır olmayan bir durdurma nedeni olan indirmeler Download.STATE_STOPPED
durumunda olur. Durdurma nedenleri DownloadIndex
içinde kalıcı olarak saklanır ve uygulama işlemi sonlandırılıp daha sonra yeniden başlatılırsa da saklanır.
Tüm indirmeleri 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);
İndirmeler duraklatıldığında Download.STATE_QUEUED
durumunda olurlar.
Durdurma nedenlerini ayarlamanın aksine bu yaklaşım herhangi bir durum değişikliğini korumaz. Yalnızca DownloadManager
çalışma zamanı durumunu etkiler.
İlerleme durumu indirme gereksinimlerini ayarlama
Requirements
, indirmelerin devam etmesi için karşılanması gereken kısıtlamaları belirtmek amacıyla kullanılabilir. Gereksinimler, yukarıdaki örnekte olduğu gibi, DownloadManager
oluşturulurken DownloadManager.setRequirements()
çağrısı yapılarak ayarlanabilir. Bunlar, DownloadService
öğesine bir komut gönderilerek dinamik bir şekilde de 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);
Gereksinimler karşılanmadığı için indirme işlemi devam edemediğinde işlem Download.STATE_QUEUED
durumunda olur. Karşılanmayan koşulları DownloadManager.getNotMetRequirements()
ile sorgulayabilirsiniz.
Maksimum paralel indirme sayısı ayarlanıyor
Maksimum paralel indirme sayısı DownloadManager.setMaxParallelDownloads()
çağrısı yapılarak ayarlanabilir. Bu işlem normalde, yukarıdaki örnekte olduğu gibi DownloadManager
oluşturulurken yapılır.
Maksimum paralel indirme sayısı zaten devam ettiğinden indirme işlemi devam edemediğinde işlem Download.STATE_QUEUED
durumunda olur.
İndirilenleri sorgulama
Bir DownloadManager
öğesinin DownloadIndex
öğesi, tamamlanmış veya başarısız olanlar da dahil olmak üzere tüm indirmelerin durumu için sorgulanabilir. DownloadIndex
, DownloadManager.getDownloadIndex()
çağrısı yapılarak elde edilebilir. Tüm indirmelerin üzerinde yinelenen bir imleç, DownloadIndex.getDownloads()
çağrısıyla elde edilebilir. Alternatif olarak, tek bir indirmenin durumu DownloadIndex.getDownload()
çağrısı yapılarak sorgulanabilir.
DownloadManager
, yalnızca mevcut (yani tamamlanmamış veya başarısız) indirmelerin durumunu döndüren DownloadManager.getCurrentDownloads()
sağlar. Bu yöntem, bildirimleri ve mevcut indirmelerin ilerleme durumunu ve durumunu gösteren diğer kullanıcı arayüzü bileşenlerini güncellemek için kullanışlıdır.
İndirilen içerikler dinleniyor
Mevcut indirmelerin durumu değiştiğinde bildirim almak için DownloadManager
öğesine bir işleyici 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ı, çevrimiçi içeriğin oynatılmasına benzer; tek fark verilerin ağ üzerinden değil, indirilen öğeden Cache
okunmasıdır.
İndirilen içeriği oynatmak için indirme işleminde kullanılan Cache
örneğini kullanarak bir CacheDataSource.Factory
oluşturun ve oynatıcıyı oluştururken bunu 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();
İndirilmemiş içeriği oynatmak için de aynı oynatıcı örneği kullanılacaksa oynatma sırasında 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, oynatmak üzere indirilen içeriğe erişebilir. Böylelikle bir indirme işlemini yürütmek, ilgili MediaItem
değerini oynatıcıya iletmek kadar basittir. Bir MediaItem
, Download.request.toMediaItem
kullanılarak Download
yönteminden veya DownloadRequest.toMediaItem
kullanılarak doğrudan bir DownloadRequest
aracından alınabilir.
MediaSource yapılandırması
Yukarıdaki örnek, indirme önbelleğinin tüm MediaItem
'lerin oynatılması için kullanılabilir olmasını sağlar. İndirme önbelleğini, doğrudan oynatıcıya geçirilebilecek ayrı 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 kanalı içerir. Genellikle aynı içeriği farklı kalitelerde (ör. SD, HD ve 4K video parçaları) içeren birden fazla parça bulunur. Ayrıca, farklı içeriklere sahip aynı türde 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 DownloadHelper
kullanılabilir. Tipik bir DownloadHelper
kullanımı için şu adımlar izlenir:
DownloadHelper.forMediaItem
yöntemlerinden birini kullanarak birDownloadHelper
oluşturun. Yardımcıyı hazırlayın ve geri çağırmayı 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
ile varsayılan olarak seçilen parçaları denetleyin veclearTrackSelections
,replaceTrackSelections
veaddTrackSelection
kullanarak düzenlemeler yapın. getDownloadRequest
numarasını arayarak seçili parçalar için birDownloadRequest
oluşturun. İstek, yukarıda açıklandığı gibi, indirme işlemini eklemek içinDownloadService
cihazınıza iletilebilir.release()
öğesini kullanarak yardımcıyı bırakın.
İndirilen uyarlanabilir içeriğin oynatılması, yukarıda açıklandığı gibi oynatıcının yapılandırılmasını ve ilgili MediaItem
değerinin iletilmesini gerektirir.
MediaItem
oluşturulurken MediaItem.localConfiguration.streamKeys
, DownloadRequest
kapsamındakilerle eşleşecek şekilde ayarlanmalıdır. Böylece oynatıcı yalnızca indirilen parçaların alt kümesini oynatmaya çalışır. MediaItem
oluşturmak için Download.request.toMediaItem
ve DownloadRequest.toMediaItem
kullanılması bu işi sizin yerinize halleder.