ExoPlayer มีฟังก์ชันการดาวน์โหลดสื่อเพื่อเล่นแบบออฟไลน์ ส่วนใหญ่
คุณควรดาวน์โหลดต่อ
แม้แอปของคุณจะอยู่ใน
พื้นหลัง สำหรับกรณีการใช้งานเหล่านี้ แอปของคุณควรคลาสย่อย DownloadService
และ
ส่งคำสั่งไปยังบริการเพื่อเพิ่ม นำออก และควบคุมการดาวน์โหลด
แผนภาพต่อไปนี้จะแสดงคลาสหลักที่เกี่ยวข้อง
DownloadService
: รวมDownloadManager
และส่งต่อคำสั่งไปยังคำสั่งนั้น บริการช่วยให้DownloadManager
ทำงานต่อไปได้แม้ว่าแอปจะเปิดอยู่ พื้นหลังDownloadManager
: จัดการการดาวน์โหลดหลายรายการ โหลด (และจัดเก็บ) สถานะตั้งแต่ (และถึง)DownloadIndex
เริ่มต้นและหยุดการดาวน์โหลดที่พิจารณาจาก ตามข้อกำหนดต่างๆ เช่น การเชื่อมต่อเครือข่าย และอื่นๆ หากต้องการดาวน์โหลด เนื้อหา ผู้จัดการจะอ่านข้อมูลที่ดาวน์โหลดจากHttpDataSource
แล้วเขียนลงในCache
DownloadIndex
: คงสถานะของการดาวน์โหลด
การสร้าง DownloadService
หากต้องการสร้าง DownloadService
ให้คลาสย่อยและใช้
วิธีการเชิงนามธรรม:
getDownloadManager()
: แสดงDownloadManager
ที่จะใช้getScheduler()
: แสดงผลScheduler
ที่ไม่บังคับ ซึ่งสามารถรีสตาร์ท เมื่อต้องการให้การดาวน์โหลดที่รอดำเนินการเป็นไปตามข้อกำหนด ExoPlayer มีการใช้งานดังต่อไปนี้PlatformScheduler
ซึ่งใช้ JobScheduler (API ขั้นต่ำคือ 21) โปรดดู PlatformScheduler เป็น Javadocs สำหรับข้อกำหนดสิทธิ์ของแอปWorkManagerScheduler
ซึ่งใช้ WorkManager
getForegroundNotification()
: แสดงการแจ้งเตือนเมื่อ บริการทำงานอยู่ในเบื้องหน้า คุณสามารถใช้DownloadNotificationHelper.buildProgressNotification
เพื่อสร้าง ในรูปแบบเริ่มต้น
สุดท้าย ให้กำหนดบริการในไฟล์ AndroidManifest.xml
ดังนี้
<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>
ดู DemoDownloadService
และ AndroidManifest.xml
ใน ExoPlayer
แอปเดโมเพื่อเป็นตัวอย่างให้เห็นจริง
การสร้าง DownloadManager
ข้อมูลโค้ดต่อไปนี้แสดงวิธีสร้างอินสแตนซ์ DownloadManager
ซึ่ง getDownloadManager()
จะส่งคืนได้ใน DownloadService
ของคุณดังนี้
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);
ดูตัวอย่างที่ชัดเจนได้ที่ DemoUtil
ในแอปเดโม
กำลังเพิ่มการดาวน์โหลด
หากต้องการเพิ่มการดาวน์โหลด ให้สร้าง DownloadRequest
แล้วส่งไปยัง
DownloadService
สำหรับสตรีมแบบปรับอัตโนมัติ ให้ใช้ DownloadHelper
เพื่อช่วย
สร้าง DownloadRequest
ดังต่อไปนี้
ตัวอย่าง แสดงวิธีสร้างคำขอดาวน์โหลด
Kotlin
val downloadRequest = DownloadRequest.Builder(contentId, contentUri).build()
Java
DownloadRequest downloadRequest = new DownloadRequest.Builder(contentId, contentUri).build();
ในตัวอย่างนี้ contentId
คือตัวระบุเนื้อหาที่ไม่ซ้ำกัน ในกรณีง่ายๆ ฟิลด์
contentUri
มักใช้เป็น contentId
ได้ แต่แอปใช้งานได้ฟรี
รูปแบบรหัสใดก็ตามที่เหมาะกับกรณีการใช้งานของตนมากที่สุด DownloadRequest.Builder
ยังมี
ตัวตั้งค่าที่ไม่บังคับบางอย่าง เช่น สามารถใช้ setKeySetId
และ setData
เพื่อ
ตั้งค่า DRM และข้อมูลที่กำหนดเองซึ่งแอปต้องการเชื่อมโยงกับการดาวน์โหลด
ตามลำดับ คุณยังระบุประเภท MIME ของเนื้อหาโดยใช้ setMimeType
ได้ด้วย
เพื่อเป็นคำแนะนำในกรณีที่ไม่สามารถอนุมานประเภทเนื้อหาจาก contentUri
ได้
เมื่อสร้างแล้ว จะสามารถส่งคำขอไปยัง DownloadService
เพื่อเพิ่ม
ดาวน์โหลด:
Kotlin
DownloadService.sendAddDownload( context, MyDownloadService::class.java, downloadRequest, /* foreground= */ false )
Java
DownloadService.sendAddDownload( context, MyDownloadService.class, downloadRequest, /* foreground= */ false);
ในตัวอย่างนี้ MyDownloadService
คือคลาสย่อย DownloadService
ของแอป และ
พารามิเตอร์ foreground
จะควบคุมว่าบริการจะเริ่มต้นใน
เบื้องหน้า หากแอปอยู่เบื้องหน้าอยู่แล้ว foreground
โดยปกติควรตั้งค่าพารามิเตอร์เป็น false
เนื่องจาก DownloadService
จะ
วางตัวเองไว้เบื้องหน้าหากตัดสินว่าอุปกรณ์มีงานที่ต้องทำ
กำลังนำรายการที่ดาวน์โหลดออก
คุณนำการดาวน์โหลดออกได้โดยส่งคำสั่งนำออกไปยัง DownloadService
ที่ contentId
ระบุว่าการดาวน์โหลดจะถูกลบออก:
Kotlin
DownloadService.sendRemoveDownload( context, MyDownloadService::class.java, contentId, /* foreground= */ false )
Java
DownloadService.sendRemoveDownload( context, MyDownloadService.class, contentId, /* foreground= */ false);
นอกจากนี้คุณยังนำข้อมูลที่ดาวน์โหลดไว้ทั้งหมดออกได้ด้วย
DownloadService.sendRemoveAllDownloads
การเริ่มและหยุดการดาวน์โหลด
การดาวน์โหลดจะดำเนินการหากเป็นไปตามเงื่อนไข 4 ข้อต่อไปนี้เท่านั้น
- การดาวน์โหลดไม่มีเหตุผลที่หยุด
- การดาวน์โหลดไม่หยุดชั่วคราว
- เป็นไปตามข้อกำหนดสำหรับการดาวน์โหลด ข้อกำหนดสามารถระบุ ประเภทเครือข่ายที่อนุญาต และกำหนดว่าอุปกรณ์ควร ไม่มีความเคลื่อนไหวหรือเชื่อมต่อกับที่ชาร์จ
- การดาวน์โหลดพร้อมกันต้องไม่เกินจำนวนครั้งสูงสุด
เงื่อนไขทั้งหมดนี้สามารถควบคุมได้โดยการส่งคำสั่งไปยัง
DownloadService
การตั้งค่าและการล้างเหตุผลที่หยุดดาวน์โหลด
คุณกำหนดเหตุผลสำหรับการหยุดดาวน์โหลดรายการหนึ่งหรือทุกรายการได้โดยทำดังนี้
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
จะเป็นค่าใดก็ได้ที่ไม่ใช่ 0 (Download.STOP_REASON_NONE = 0
คือ
ค่าพิเศษหมายความว่าการดาวน์โหลดจะไม่หยุดทำงาน) แอปที่มี
เหตุผลหลายประการในการหยุดดาวน์โหลดอาจใช้ค่าที่ต่างกันเพื่อติดตาม
เกี่ยวกับสาเหตุที่การดาวน์โหลดแต่ละครั้งหยุดลง การตั้งค่าและล้างเหตุผลที่หยุดสำหรับ
การดาวน์โหลดจะทำงานในลักษณะเดียวกับการตั้งค่าและล้างเหตุผลที่หยุด
ดาวน์โหลดครั้งเดียว เว้นแต่ว่าควรตั้งค่า contentId
เป็น null
เมื่อการดาวน์โหลดมีเหตุผลที่ทำให้หยุดโดยไม่เป็น 0 การดาวน์โหลดจะอยู่ใน
รัฐDownload.STATE_STOPPED
เหตุผลในการหยุดจะคงอยู่ใน
ระบบจะเก็บรักษา DownloadIndex
ไว้หากกระบวนการสมัครหยุดทำงานและ
รีสตาร์ทในภายหลัง
การหยุดดาวน์โหลดทั้งหมดชั่วคราวแล้วกลับมาดำเนินการอีกครั้ง
การดาวน์โหลดทั้งหมดสามารถหยุดชั่วคราวและทำต่อได้ดังนี้
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);
เมื่อการดาวน์โหลดหยุดชั่วคราว วิดีโอที่ดาวน์โหลดจะอยู่ในสถานะ Download.STATE_QUEUED
วิธีนี้ไม่เก็บสถานะใดๆ ไว้ ซึ่งแตกต่างจากการตั้งค่าเหตุผลที่หยุด
การเปลี่ยนแปลง โดยจะส่งผลต่อสถานะรันไทม์ของ DownloadManager
เท่านั้น
การตั้งค่าข้อกำหนดเพื่อให้การดาวน์โหลดมีความคืบหน้า
Requirements
สามารถใช้เพื่อระบุข้อจำกัดที่ต้องปฏิบัติตามสำหรับ
ดาวน์โหลดเพื่อดำเนินการต่อ สามารถตั้งข้อกำหนดโดยการโทร
DownloadManager.setRequirements()
เมื่อสร้าง DownloadManager
เช่น
ตัวอย่างด้านบน นอกจากนี้ยังสามารถเปลี่ยนได้แบบไดนามิกโดยการส่งคำสั่ง
เป็น DownloadService
:
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);
เมื่อดำเนินการดาวน์โหลดไม่ได้เนื่องจากไม่เป็นไปตามข้อกำหนด
จะอยู่ในสถานะ Download.STATE_QUEUED
คุณสามารถค้นหา "ไม่พบ"
ด้วย DownloadManager.getNotMetRequirements()
การตั้งค่าจำนวนการดาวน์โหลดพร้อมกันสูงสุด
สามารถกำหนดจำนวนการดาวน์โหลดพร้อมกันสูงสุดได้โดยการเรียกใช้
DownloadManager.setMaxParallelDownloads()
โดยปกติจะทำเมื่อ
สร้าง DownloadManager
ตามตัวอย่างด้านบน
เมื่อดาวน์โหลดต่อไม่ได้เนื่องจากถึงจำนวนการดาวน์โหลดพร้อมกันสูงสุดแล้ว
อยู่ระหว่างดำเนินการ และจะอยู่ในสถานะ Download.STATE_QUEUED
ค้นหาการดาวน์โหลด
คุณสามารถค้นหา DownloadIndex
ของ DownloadManager
เพื่อดูสภาวะของ
รวมถึงรายการที่เสร็จสมบูรณ์หรือล้มเหลว DownloadIndex
สามารถรับได้โดยโทรไปที่ DownloadManager.getDownloadIndex()
เคอร์เซอร์
ทำซ้ำจากการดาวน์โหลดทั้งหมด จากนั้นจะสามารถรับได้ด้วยการเรียก
DownloadIndex.getDownloads()
หรือสถานะของการดาวน์โหลดครั้งเดียว
คุณสามารถค้นหาได้โดยโทรไปที่ DownloadIndex.getDownload()
DownloadManager
ยังมี DownloadManager.getCurrentDownloads()
ซึ่งมี
จะแสดงสถานะของการดาวน์โหลดปัจจุบัน (เช่น การดาวน์โหลดไม่เสร็จสิ้นหรือล้มเหลว) เท่านั้น ช่วงเวลานี้
มีประโยชน์ในการอัปเดตการแจ้งเตือนและคอมโพเนนต์ UI อื่นๆ ที่แสดง
ความคืบหน้าและสถานะของการดาวน์โหลดปัจจุบัน
กำลังฟังการดาวน์โหลด
คุณเพิ่ม Listener ลงใน DownloadManager
เพื่อให้ทราบข้อมูลเมื่อฟังอยู่ได้
การดาวน์โหลดเปลี่ยนสถานะ:
Kotlin
downloadManager.addListener( object : DownloadManager.Listener { // Override methods of interest here. } )
Java
downloadManager.addListener( new DownloadManager.Listener() { // Override methods of interest here. });
โปรดดู DownloadManagerListener
ในชั้นเรียน DownloadTracker
ของแอปเดโมสำหรับ
ตัวอย่างที่เป็นรูปธรรม
กำลังเล่นเนื้อหาที่ดาวน์โหลด
การเล่นเนื้อหาที่ดาวน์โหลดคล้ายกับการเล่นเนื้อหาออนไลน์ เว้นแต่ว่า
จะอ่านข้อมูลจากการดาวน์โหลด Cache
แทนการอ่านผ่านเครือข่าย
หากต้องการเล่นเนื้อหาที่ดาวน์โหลด ให้สร้าง CacheDataSource.Factory
โดยใช้
Cache
อินสแตนซ์ที่ใช้สําหรับดาวน์โหลดและแทรกอินสแตนซ์ลงใน
DefaultMediaSourceFactory
เมื่อสร้างโปรแกรมเล่น:
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();
หากจะมีการใช้อินสแตนซ์ของโปรแกรมเล่นเดียวกันเพื่อเล่นเนื้อหาที่ไม่ได้ดาวน์โหลดด้วย
ควรกําหนดค่า CacheDataSource.Factory
เป็นแบบอ่านอย่างเดียวเพื่อหลีกเลี่ยง
ดาวน์โหลดเนื้อหานั้น
ในระหว่างการเล่นด้วย
เมื่อกำหนดค่าโปรแกรมเล่นด้วย CacheDataSource.Factory
แล้ว ระบบจะดำเนินการ
เข้าถึงเนื้อหาที่ดาวน์โหลดเพื่อเล่นได้ ตอนนี้
เพียงแค่ส่ง MediaItem
ที่เกี่ยวข้องไปให้ผู้เล่น MediaItem
สามารถหาได้จาก Download
โดยใช้ Download.request.toMediaItem
หรือ
จาก DownloadRequest
โดยตรงด้วย DownloadRequest.toMediaItem
การกำหนดค่า MediaSource
ตัวอย่างก่อนหน้านี้ทำให้แคชดาวน์โหลดสามารถเล่นได้ทั้งหมด
MediaItem
วินาที คุณยังทำให้แคชดาวน์โหลดพร้อมใช้งานสำหรับ
MediaSource
อินสแตนซ์แต่ละรายการ ซึ่งสามารถส่งผ่านไปยังโปรแกรมเล่นโดยตรง:
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();
การดาวน์โหลดและเล่นสตรีมแบบปรับเปลี่ยนได้
โดยปกติสตรีมแบบปรับอัตโนมัติ (เช่น DASH, SmoothStreaming และ HLS) จะประกอบด้วย เส้นทางสื่อ มักจะมีหลายแทร็กที่มีเนื้อหาเดียวกันใน คุณภาพที่ต่างกัน (เช่น แทร็กวิดีโอ SD, HD และ 4K) นอกจากนี้ยังอาจมี แทร็กประเภทเดียวกันหลายแทร็กที่มีเนื้อหาแตกต่างกัน (เช่น หลายแทร็ก แทร็กเสียงในภาษาต่างๆ)
สำหรับการเล่นแบบสตรีม
สามารถใช้ตัวเลือกแทร็กเพื่อเลือก
เมื่อมีการเล่นแทร็ก ในทำนองเดียวกัน ในการดาวน์โหลด สามารถใช้ DownloadHelper
เพื่อ
ให้เลือกแทร็กที่จะดาวน์โหลด การใช้งานทั่วไปของ DownloadHelper
ให้ทำตามขั้นตอนต่อไปนี้
- สร้าง
DownloadHelper
โดยใช้หนึ่งในDownloadHelper.forMediaItem
โปรดเตรียมผู้ช่วยไว้ให้พร้อมและรอให้ระบบติดต่อกลับ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);
- (ไม่บังคับ) ตรวจสอบแทร็กเริ่มต้นที่เลือกโดยใช้
getMappedTrackInfo
และgetTrackSelections
แล้วทำการปรับเปลี่ยนโดยใช้clearTrackSelections
replaceTrackSelections
และaddTrackSelection
- สร้าง
DownloadRequest
สำหรับแทร็กที่เลือกโดยการโทรgetDownloadRequest
สามารถส่งคำขอไปยังDownloadService
ของคุณเพื่อ เพิ่มการดาวน์โหลด ตามที่อธิบายไว้ข้างต้น - ปล่อย Assistant โดยใช้
release()
ต้องกำหนดค่าโปรแกรมเล่นและการเล่นเนื้อหาแบบปรับอัตโนมัติที่ดาวน์โหลดมา
ส่ง MediaItem
ที่เกี่ยวข้องตามที่อธิบายไว้ข้างต้น
เมื่อสร้าง MediaItem
ต้องกำหนด MediaItem.localConfiguration.streamKeys
เป็น
ตั้งค่าให้ตรงกับข้อมูลใน DownloadRequest
เพื่อให้โปรแกรมเล่นพยายาม
เล่นแทร็กย่อยที่ดาวน์โหลดไว้ การใช้
Download.request.toMediaItem
และ DownloadRequest.toMediaItem
เพื่อสร้าง
MediaItem
จะจัดการเรื่องนี้ให้คุณ