Android文件下载及在Jetpack Compose中使用

前言

本文使用OkDownloader进行文件下载

https://github.com/ydxlt/okdownloader

https://ydxlt.github.io/okdownloader/

方法

添加依赖

1
implementation("io.github.ydxlt:okdownloader:1.0.0")

初始化

1
2
3
4
5
6
val downloader = Downloader.Builder().build()
val request = Download.Request.Builder()
.url(it.url)
.into(it.savepath) // or into(file)
.build()
val call = downloader.newCall(request)

调用

同步

1
call.execute()

异步调用

1
call.enqueue()

取消

1
call.cancel()

同步和异步都支持回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
call.execute(object : Download.Callback {
override fun onStart(call: Download.Call) {

}

override fun onSuccess(call: Download.Call, response: Download.Response) {

}

override fun onFailure(call: Download.Call, response: Download.Response) {

}

override fun onLoading(call: Download.Call, current: Long, total: Long) {

}
})

下载工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import com.billbook.lib.downloader.Download
import com.billbook.lib.downloader.Downloader
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.LinkedList
import java.util.Queue

object DownLoadUtils {
val queue: Queue<DownloadItem> = LinkedList()
var callbackList = mutableListOf<DownloadCallback>()
var isRunning = false

/**
* 页面启动 添加回调
*/
fun addCallback(callback: DownloadCallback) {
callbackList.add(callback)
}


/**
* 页面关闭 删除回调
*/
fun removeCallback(callback: DownloadCallback) {
callbackList.remove(callback)
}


/**
* 下载文件
*/
fun addDownload(url: String, tag: String, savepath: String) {
queue.add(DownloadItem(url, tag, savepath, 0))
downloadAction()
}

private fun downloadAction() {
if (isRunning) {
return
}
val coroutineScope = CoroutineScope(Dispatchers.IO)
coroutineScope.launch {
while (queue.size > 0) {
isRunning = true

val downItem = queue.peek()
downItem?.let {
try {
val downloader = Downloader.Builder().build()
val request = Download.Request.Builder()
.url(it.url)
.into(it.savepath) // or into(file)
.build()
val call = downloader.newCall(request)
call.execute(object : Download.Callback {
override fun onStart(call: Download.Call) {
for (downloadCallback in callbackList) {
downloadCallback.onStart(downItem)
}
}

override fun onSuccess(call: Download.Call, response: Download.Response) {
// do your job
queue.poll()
for (downloadCallback in callbackList) {
downloadCallback.onSuccess(downItem)
}
}

override fun onFailure(call: Download.Call, response: Download.Response) {
// do your job

queue.poll()
for (downloadCallback in callbackList) {
downloadCallback.onFailure(downItem)
}
}

override fun onLoading(call: Download.Call, current: Long, total: Long) {
for (downloadCallback in callbackList) {
val progress = (current * 100 / total).toInt()
if (progress != downItem.progress) {
downItem.progress = progress
downloadCallback.onLoading(downItem)
}
}
}
})
} catch (e: Exception) {
queue.poll()
for (downloadCallback in callbackList) {
downloadCallback.onFailure(downItem)
}
}
}

}
isRunning = false
}

}
}

data class DownloadItem(val url: String, val tag: String, val savepath: String, var progress: Int)

interface DownloadCallback {
fun onStart(downItem: DownloadItem)
fun onSuccess(downItem: DownloadItem)
fun onFailure(downItem: DownloadItem)
fun onLoading(downItem: DownloadItem)
}

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
DisposableEffect(Unit) {
// 初始化操作,类似于 onCreate()
val callback = object : DownloadCallback {
override fun onStart(downItem: DownloadItem) {
Log.i("下载", "下载开始")
}

override fun onSuccess(downItem: DownloadItem) {
Log.i("下载", "下载成功")
}

override fun onFailure(downItem: DownloadItem) {
Log.i("下载", "下载失败")
}

override fun onLoading(downItem: DownloadItem) {
Log.i("下载", "下载进度${downItem.progress}")
}

}

DownLoadUtils.addCallback(callback)

onDispose {
// 清理资源,类似于 onDestroy()
DownLoadUtils.removeCallback(callback)
}
}

下载调用

1
2
3
4
5
DownLoadUtils.addDownload(
CommonData.fileUrl + appItem.apkPath,
appItem.appPackage,
File(baseContext.getExternalFilesDir(null), appItem.appPackage + ".apk").absolutePath
)