使用嵌套的 CoroutineScopes 上传图片并跟踪它们

Using nested CoroutineScopes to upload images and keeping track of them

我是 android 协程的新手我的要求

  1. 需要上传20张图片
  2. 跟踪上传(至少当它完成时我需要隐藏每张图片的进度条)
  3. 上传所有图片后还需要启用“下一步”按钮 这是我的尝试:

private fun startUploading(){
    // Get AWS data
    val accessKey = sharedPreferences.getString(getString(R.string.aws_access_key), "").toString()
    val secretKey = sharedPreferences.getString(getString(R.string.aws_secret_key), "").toString()
    val bucketName = sharedPreferences.getString(getString(R.string.aws_bucket_name), "").toString()
    val region = sharedPreferences.getString(getString(R.string.aws_region), "").toString()
    val distributionUrl = sharedPreferences.getString(getString(R.string.aws_distribution_url), "").toString()

    var totalImagesNeedToUpload = 0
    var totalImagesUploaded = 0
    CoroutineScope(Dispatchers.IO).launch {
        for (i in allCapturedImages.indices) {
            val allImageFiles = allCapturedImages[i].viewItem.ImageFiles
            totalImagesNeedToUpload += allImageFiles.size
            for (j in allImageFiles.indices) {
                CoroutineScope(Dispatchers.IO).launch {
                    while (true) {
                        val internetActive = utilsClassInstance.hasInternetConnected()
                        if (internetActive){
                            try {
                                val file = allImageFiles[j]
                                if (!file.uploaded) {
                                    // Upload the file
                                    val cfUrl = utilsClassInstance.uploadFile(file.imageFile, accessKey, secretKey, bucketName, region, distributionUrl)

                                    // Set the uploaded status to true
                                    file.uploaded = true
                                    file.uploadedUrl = cfUrl

                                    // Increment the count of total uploaded images
                                    totalImagesUploaded += 1

                                    // Upload is done for that particular set image
                                    CoroutineScope(Dispatchers.Main).launch {
                                        mainRecyclerAdapter?.uploadCompleteForViewItemImage(i, j, cfUrl)
                                        // Set the next button enabled
                                        if (totalImagesUploaded == totalImagesNeedToUpload){
                                            binding.btnNext.isEnabled = true
                                        }
                                    }
                                    break
                                }else{
                                    totalImagesUploaded += 1
                                    break
                                }
                            } catch (e: Exception) {
                                println(e.printStackTrace())
                            }
                        }
                    }
                    CoroutineScope(Dispatchers.Main).launch {
                        if (totalImagesUploaded == totalImagesNeedToUpload){
                            updateProgressForAllImages()
                            binding.btnNext.isEnabled = true
                        }
                    }
                }
            }
        }
    }
}

    fun uploadFile(file: File, accessKey:String, secretKey:String, bucketName: String, region:String, distributionUrl: String): String{
    // Create a S3 client
    val s3Client = AmazonS3Client(BasicAWSCredentials(accessKey, secretKey))
    s3Client.setRegion(Region.getRegion(region))

    // Create a put object
    val por = PutObjectRequest(bucketName, file.name, file)
    s3Client.putObject(por)

    // Override the response headers
    val override = ResponseHeaderOverrides()
    override.contentType = "image/jpeg"

    // Generate the url request
    val urlRequest = GeneratePresignedUrlRequest(bucketName, file.name)
    urlRequest.responseHeaders = override

    // Get the generated url
    val url = s3Client.generatePresignedUrl(urlRequest)
    return url.toString().replace("https://${bucketName}.s3.amazonaws.com/", distributionUrl)
}        
  1. 我总共需要上传“n”张图片
  2. 每张图片都在不同的协程中上传,因为我需要并行上传

整个问题是如何知道所有图像都已上传并启用下一步按钮?

您的代码看起来很松散。您有一个无限循环检查网络可用性。您在此处有一个嵌套循环来上传图像(为什么?)。您正在创建大量协程作用域并且无法控制它们

根据你在问题中提到的3个要求,你可以这样做:

val imagesToUpload: List<File> = /* ... */
var filesUploaded = 0
lifecycleScope.launchWhenStarted { 
    coroutineScope { // This will return only when all child coroutines have finished
        imagesToUpload.forEach { imageFile ->
            launch { // Run every upload in parallel
                val url = utilsClassInstance.uploadFile(file.imageFile, ...) // Assuming this is a non-blocking suspend function.
                filesUploaded++
                // Pass the `url` to your adapter to display the image
                binding.progressBar.progress = (filesUploaded * 100) / imagesToUpload.size // Update progress bar
            }
        }
    }
    // All images have been uploaded at this point.
    binding.btnNext.enabled = true
}

理想情况下,您应该使用 viewModelScope 并且上传代码应该在存储库中,但是由于您似乎没有合适的架构,我使用了 lifecycleScope你可以进入 ActivityFragment