首页 > 解决方案 > 我们可以在 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"

标签: androidkotlinkotlin-coroutinesandroid-download-managerktor

解决方案


应该是可以的。

  1. 创建另一个将遍历要下载的文件列表的函数。
  2. 使用新函数,使用异步启动协程函数 - 这允许分别对逻辑流、顺序行为或异步行为进行更多控制。

例如fun downloadBatch(list: List<Uri>) { GlobalScope.async(Dispatchers.IO) { //logic goes here }}

注意:GlobalScope 只是一个简单的例子——不建议在现场制作中使用。

  1. 在迭代器/for 循环中,调用一个函数来下载单个文件。此特定功能应在开头附加挂起,例如suspend fun downloadFile(uri: Uri)

注意:挂起的函数本身不会使用任何线程逻辑,它依赖于嵌套在函数式协程中。

  1. 继续使用 rxJava 或尝试 LiveData 来广播您的文件。

推荐阅读