android - 我们可以在 Android Kotlin 的单个协程中下载多个文件吗
问题描述
您好所有开发人员请尽可能多地整理我的查询。
我正在开发相册应用程序。在这里,当用户单击特定相册时,我们应该将所有相关图像下载到该特定相册。
例如专辑名称是树,因此专辑有多个图像 url 的数组。所以我应该通过 url 的数组下载该专辑中的所有图像
例如:imageArray = arrayOf("url1","url2","url3","url4",....等 url(n))
我应该将它们放入 for 循环或递归中,然后我应该在完成后将它们下载到 (n) 个 url。
我在这里为一个文件下载编写了片段我的疑问是如何继续下载多个文件。
我应该对所有文件下载使用相同的协程,还是对一个文件使用一个协程
CoroutineScope(Dispatchers.IO).launch {
**//here itself i can run for loop or else any other robust/proper way to do this requirement.**
ktor.downloadFile(outputStream, url).collect {
withContext(Dispatchers.Main) {
when (it) {
is DownloadResult.Success -> {
**//on success of one file download should i call recursively to download one more file by this method - private fun downloadFile(context: Context, url: String, file: Uri)**
viewFile(file)
}
下面是下载单个文件的代码
private fun downloadFile(context: Context, url: String, file: Uri) {
val ktor = HttpClient(Android)
contentResolver.openOutputStream(file)?.let { outputStream ->
CoroutineScope(Dispatchers.IO).launch {
ktor.downloadFile(outputStream, url).collect {
withContext(Dispatchers.Main) {
when (it) {
is DownloadResult.Success -> {
viewFile(file)
}
is DownloadResult.Error -> {
}
is DownloadResult.Progress -> {
txtProgress.text = "${it.progress}"
}
}
}
}
}
}
}
suspend fun HttpClient.downloadFile(file: OutputStream, url: String): Flow<DownloadResult> {
return flow {
try {
val response = call {
url(url)
method = HttpMethod.Get
}.response
val data = ByteArray(response.contentLength()!!.toInt())
var offset = 0
do {
val currentRead = response.content.readAvailable(data, offset, data.size)
offset += currentRead
val progress = (offset * 100f / data.size).roundToInt()
emit(DownloadResult.Progress(progress))
} while (currentRead > 0)
response.close()
if (response.status.isSuccess()) {
withContext(Dispatchers.IO) {
file.write(data)
}
emit(DownloadResult.Success)
} else {
emit(DownloadResult.Error("File not downloaded"))
}
} catch (e: TimeoutCancellationException) {
emit(DownloadResult.Error("Connection timed out", e))
} catch (t: Throwable) {
emit(DownloadResult.Error("Failed to connect"))
}
}
}
sealed class DownloadResult {
object Success : DownloadResult()
data class Error(val message: String, val cause: Exception? = null) : DownloadResult()
data class Progress(val progress: Int): DownloadResult()
}
我用过的 Gradle 文件
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3'
implementation "io.ktor:ktor-client-android:1.2.5"
解决方案
应该是可以的。
- 创建另一个将遍历要下载的文件列表的函数。
- 使用新函数,使用异步或启动协程函数 - 这允许分别对逻辑流、顺序行为或异步行为进行更多控制。
例如fun downloadBatch(list: List<Uri>) { GlobalScope.async(Dispatchers.IO) { //logic goes here }}
注意:GlobalScope 只是一个简单的例子——不建议在现场制作中使用。
- 在迭代器/for 循环中,调用一个函数来下载单个文件。此特定功能应在开头附加挂起,例如
suspend fun downloadFile(uri: Uri)
注意:挂起的函数本身不会使用任何线程逻辑,它依赖于嵌套在函数式协程中。
- 继续使用 rxJava 或尝试 LiveData 来广播您的文件。
推荐阅读
- python - 网站拒绝使用 Selenium 获取请求
- php - 用于 img 标签的 Laravel 自定义路径
- azure - Microsoft Azure 应用程序在收到长 URL 时输出错误。我该如何解决?
- dll - 在 WSL 下使用 GDB 调试 DLL
- python - 如何调整极坐标图的刻度标签?
- python - 日期提取正则表达式适用于在线测试工具,但不适用于 python 正则表达式库
- javascript - 我如何制作一个输入类型的提交按钮,填写表格后才能使用
- python - 单击一次后如何禁用按钮?
- django - Django 将数据传递到 Google Charts
- c# - 为什么“is”-运算符在 if 的范围内比 if 更长?