本文详细介绍了如何在 Android 项目中使用 Aria 下载框架,并通过封装、任务队列管理、网络状态检查以及持久化存储等优化手段,提升下载功能的代码质量和用户体验。主要内容包括:
1.封装下载逻辑:将 Aria 的下载逻辑封装到一个单独的类中,便于复用和维护。
2.任务队列管理:支持多个下载任务的有序执行,避免同时下载过多文件。
3.网络状态检查:在下载前检查网络状态,避免在无网络时启动下载任务。
4.持久化存储:使用 Room 数据库存储下载任务信息,支持应用重启后恢复下载任务。
通过本文的实践,你将掌握如何高效地使用 Aria 实现强大的下载功能,并优化代码结构和性能
以下是完整代码,包括封装下载逻辑、任务队列管理、网络状态检查以及持久化存储。
你需要引入以下库:
Aria 下载框架:
dependencies {
// Aria 核心库
implementation 'com.arialyy.aria:core:3.8.16'
// Aria 注解处理器(如果需要)
annotationProcessor 'com.arialyy.aria:compiler:3.8.16'
}
Room 数据库(用于持久化存储):
dependencies {
// Room 数据库
implementation "androidx.room:room-runtime:2.5.2"
kapt "androidx.room:room-compiler:2.5.2" // Kotlin 注解处理器
implementation "androidx.room:room-ktx:2.5.2" // 支持 Kotlin 扩展函数
}
Kotlin 协程(用于异步操作):
dependencies {
// Kotlin 协程
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1"
}
AndroidX 核心库:
dependencies {
// AndroidX 核心库
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.google.android.material:material:1.9.0'
}
完整的 build.gradle 文件:
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt' // Kotlin 注解处理器
}
android {
compileSdk 34
defaultConfig {
applicationId "com.example.myapp"
minSdk 21
targetSdk 34
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '17'
}
}
dependencies {
// Aria 下载框架
implementation 'com.arialyy.aria:core:3.8.16'
annotationProcessor 'com.arialyy.aria:compiler:3.8.16'
// Room 数据库
implementation "androidx.room:room-runtime:2.5.2"
kapt "androidx.room:room-compiler:2.5.2"
implementation "androidx.room:room-ktx:2.5.2"
// Kotlin 协程
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1"
// AndroidX 核心库
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.google.android.material:material:1.9.0'
}
代码如下:
1. 封装下载逻辑
将 Aria 的下载逻辑封装到一个单独的类中,便于复用和维护。
DownloadManager.kt
package com.example.myapp.download
import android.content.Context
import com.arialyy.aria.core.Aria
import com.arialyy.aria.core.task.DownloadTask
import com.arialyy.aria.core.common.AbsDownloadTaskListener
import com.example.myapp.utils.NetworkUtils
import com.example.myapp.utils.FileUtils
class DownloadManager(private val context: Context) {
private val downloadQueue = mutableListOf<DownloadTask>()
private var isDownloading = false
fun downloadFile(url: String, fileName: String, listener: DownloadListener) {
if (!NetworkUtils.isNetworkAvailable(context)) {
listener.onFail("No network available")
return
}
val savePath = FileUtils.getDownloadPath(context, fileName)
val task = Aria.download(context)
.load(url)
.setFilePath(savePath)
.addTaskListener(object : AbsDownloadTaskListener() {
override fun onTaskStart(task: DownloadTask) {
listener.onStart()
}
override fun onTaskRunning(task: DownloadTask) {
val progress = task.percent
val speed = task.convertSpeed
listener.onProgress(progress, speed)
}
override fun onTaskComplete(task: DownloadTask) {
listener.onComplete(savePath)
downloadQueue.remove(task)
startNextDownload()
}
override fun onTaskFail(task: DownloadTask) {
listener.onFail("Download failed")
downloadQueue.remove(task)
startNextDownload()
}
})
.create()
downloadQueue.add(task)
if (!isDownloading) {
startNextDownload()
}
}
private fun startNextDownload() {
if (downloadQueue.isNotEmpty()) {
isDownloading = true
val task = downloadQueue[0]
task.start()
} else {
isDownloading = false
}
}
interface DownloadListener {
fun onStart()
fun onProgress(progress: Int, speed: String)
fun onComplete(filePath: String)
fun onFail(error: String)
}
}
2. 工具类
FileUtils.kt:管理下载路径
package com.example.myapp.utils
import android.content.Context
import android.os.Environment
import java.io.File
object FileUtils {
fun getDownloadPath(context: Context, fileName: String): String {
val directory = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
return File(directory, fileName).absolutePath
}
}
NetworkUtils.kt:检查网络状态
package com.example.myapp.utils
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
object NetworkUtils {
fun isNetworkAvailable(context: Context): Boolean {
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val network = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
}
}
3. 在 Activity 中使用封装后的下载逻辑
MainActivity.kt
package com.example.myapp
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.myapp.download.DownloadManager
class MainActivity : AppCompatActivity() {
private lateinit var downloadManager: DownloadManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
downloadManager = DownloadManager(this)
// 下载文件的 URL 和文件名
val downloadUrl = "https://example.com/file.zip"
val fileName = "file.zip"
// 开始下载
downloadManager.downloadFile(downloadUrl, fileName, object : DownloadManager.DownloadListener {
override fun onStart() {
println("Download started")
}
override fun onProgress(progress: Int, speed: String) {
println("Download progress: $progress%, speed: $speed")
}
override fun onComplete(filePath: String) {
println("Download completed. File saved at: $filePath")
}
override fun onFail(error: String) {
println(error)
}
})
}
}
4. 持久化存储(可选)
使用 Room 数据库存储下载任务信息,以便应用重启后恢复下载任务。
DownloadTaskEntity.kt:定义实体类
package com.example.myapp.data
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "download_tasks")
data class DownloadTaskEntity(
@PrimaryKey val url: String,
val fileName: String,
val savePath: String,
val status: String // e.g., "pending", "completed", "failed"
)
DownloadTaskDao.kt:定义 DAO 接口
package com.example.myapp.data
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
@Dao
interface DownloadTaskDao {
@Insert
suspend fun insert(task: DownloadTaskEntity)
@Query("SELECT * FROM download_tasks WHERE status = :status")
suspend fun getTasksByStatus(status: String): List<DownloadTaskEntity>
@Query("UPDATE download_tasks SET status = :status WHERE url = :url")
suspend fun updateTaskStatus(url: String, status: String)
}
AppDatabase.kt:创建数据库
package com.example.myapp.data
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import android.content.Context
@Database(entities = [DownloadTaskEntity::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun downloadTaskDao(): DownloadTaskDao
companion object {
@Volatile
private var INSTANCE: AppDatabase? = null
fun getDatabase(context: Context): AppDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"app_database"
).build()
INSTANCE = instance
instance
}
}
}
}
在 DownloadManager 中使用 Room 数据库
class DownloadManager(private val context: Context) {
private val database = AppDatabase.getDatabase(context)
private val downloadQueue = mutableListOf<DownloadTask>()
private var isDownloading = false
fun downloadFile(url: String, fileName: String, listener: DownloadListener) {
if (!NetworkUtils.isNetworkAvailable(context)) {
listener.onFail("No network available")
return
}
val savePath = FileUtils.getDownloadPath(context, fileName)
val task = Aria.download(context)
.load(url)
.setFilePath(savePath)
.addTaskListener(object : AbsDownloadTaskListener() {
override fun onTaskStart(task: DownloadTask) {
listener.onStart()
saveTaskToDatabase(url, fileName, savePath, "pending")
}
override fun onTaskRunning(task: DownloadTask) {
val progress = task.percent
val speed = task.convertSpeed
listener.onProgress(progress, speed)
}
override fun onTaskComplete(task: DownloadTask) {
listener.onComplete(savePath)
updateTaskStatus(url, "completed")
downloadQueue.remove(task)
startNextDownload()
}
override fun onTaskFail(task: DownloadTask) {
listener.onFail("Download failed")
updateTaskStatus(url, "failed")
downloadQueue.remove(task)
startNextDownload()
}
})
.create()
downloadQueue.add(task)
if (!isDownloading) {
startNextDownload()
}
}
private fun saveTaskToDatabase(url: String, fileName: String, savePath: String, status: String) {
val task = DownloadTaskEntity(url, fileName, savePath, status)
database.downloadTaskDao().insert(task)
}
private fun updateTaskStatus(url: String, status: String) {
database.downloadTaskDao().updateTaskStatus(url, status)
}
private fun startNextDownload() {
if (downloadQueue.isNotEmpty()) {
isDownloading = true
val task = downloadQueue[0]
task.start()
} else {
isDownloading = false
}
}
interface DownloadListener {
fun onStart()
fun onProgress(progress: Int, speed: String)
fun onComplete(filePath: String)
fun onFail(error: String)
}
}
5. 总结
我们实现了以下功能:
1.封装下载逻辑:提高代码复用性和可维护性。
2.任务队列管理:支持多个下载任务的有序执行。
3.网络状态检查:避免在无网络时启动下载。
4.持久化存储:支持应用重启后恢复下载任务。