将多个图像上传到 Kotlin 中的 Firebase 存储时,While 循环似乎不适用于 .putFile

While loop doesn't seem to work with .putFile when uploading multiple images to Firebase storage in Kotlin

我一直在尝试将多张图片上传到 Firebase 存储。但是,我无法成功完成。我可以成功将图像(单张)上传到存储并将图像的 URL 添加到 Firestore,现在我修改了我的代码以上传最多五张图像,它可以是任意数量图片从 1 到 5.

    R.id.btn_submit -> {
    if (validateDetails()) {
        uploadImage()
    }
}

以上代码,在验证字段后调用以下函数,然后调用函数 uploadImageToCloudStoragemSelectedImageFileUriListprivate var mSelectedImageFileUriList: MutableList<Uri?>? = null。一切似乎都正常工作。

    private fun uploadImage() {
    showProgressDialog(resources.getString(R.string.please_wait))
    FirestoreClass().uploadImageToCloudStorage(
        this@AddProductActivity,
        mSelectedImageFileUriList,
        Constants.PRODUCT_IMAGE,
        Constants.PRODUCT_IMAGE_DIRECTORY_NAME,
        et_product_title.text.toString().trim { it <= ' ' }
    )
}

以下代码是我猜错的地方。

    fun uploadImageToCloudStorage(
     activity: AddProductActivity,
     imageFileURI: MutableList<Uri?>?,
     imageType: String,
     directoryName: String,
     title: String
 ) {

     var i = 0
     val imageURLList = ArrayList<String>()
     val itr = imageFileURI?.iterator()

     if (itr != null) {

         while (itr.hasNext()) {

             val sRef: StorageReference = FirebaseStorage.getInstance().getReference(
                 "/$directoryName/" + imageType + "." + Constants.getFileExtension(
                     activity,
                     imageFileURI[i]
                 )
             )
            
             sRef.putFile(imageFileURI[i]!!)
                 .addOnSuccessListener { taskSnapshot ->  
                     taskSnapshot.metadata!!.reference!!.downloadUrl
                         .addOnSuccessListener { uri ->
                             
                             if (i < imageFileURI.size) {
                                 i += 1
                                 imageURLList.add(uri.toString())

                             } else {
                                 activity.imageUploadSuccess(imageURLList)
                             }
                         }
                 }
                 .addOnFailureListener { exception ->
                     activity.hideProgressDialog()
                   Log.e(
                         activity.javaClass.simpleName,
                         exception.message,
                         exception
                     )
                 }

         }
     } else {
         Toast.makeText(
             activity,
             "There is no images in the ArrayList of URI",
             Toast.LENGTH_SHORT
         ).show()
     }
 }

编辑:收到第一个答案后。

我创建了一个 QueueSyn.kt 文件并在答案中添加了代码。图像和按钮更改为activity

class AddProductActivity : BaseActivity(), View.OnClickListener, QueueSyncCallback {

按下按钮时调用以下函数。

    private fun uploadProductImage() {

    showProgressDialog(resources.getString(R.string.please_wait))

   QueueSync(
        mSelectedImageFileUriList,
        Constants.PRODUCT_IMAGE,
        Constants.PRODUCT_IMAGE_DIRECTORY_NAME,
        et_product_title.text.toString().trim { it <= ' ' },
        this
    ).startUploading()

}

我在classAddProductActivity里面也实现了这两个方法,但是不知道里面应该放些什么。

    override fun completed(successList: MutableList<Uri>, failureList: MutableList<Uri>) {
    TODO("Not yet implemented")
}

override fun getFileExtension(uri: Uri): String {
    TODO("Not yet implemented")
}

错误:

这应该有效

import android.net.Uri
import com.google.firebase.storage.FirebaseStorage
import com.google.firebase.storage.StorageReference
import java.util.*
import kotlin.collections.ArrayList

interface QueueSyncCallback {
    fun completed(successList: MutableList<Uri>, failureList: MutableList<Uri>)
    fun getFileExtension(uri: Uri): String
}

class QueueSync(
    imageFileURI: MutableList<Uri?>?,
    private val imageType: String,
    private val directoryName: String,
    private val title: String,
    private val callback: QueueSyncCallback,
    private val maxActive: Int = 5
) {
    private val queue: LinkedList<Uri> = LinkedList()
    private val runningQueue: MutableList<Uri> = Collections.synchronizedList(
        object : ArrayList<Uri>() {
            override fun remove(element: Uri): Boolean {
                val removed = super.remove(element)

                if (isEmpty() && queue.isEmpty()) {
                    callback.completed(successList, failureList)
                } else if (queue.isNotEmpty()) {
                    addToRunningQueue()
                }
                return removed
            }
        }
    )
    private val successList: MutableList<Uri> = Collections.synchronizedList(ArrayList())
    private val failureList: MutableList<Uri> = Collections.synchronizedList(ArrayList())

    init {
        if (imageFileURI != null)
            for (uri in imageFileURI) {
                if (uri != null)
                    queue.add(uri)
            }
    }

    private fun getLocation(uri: Uri) = "/$directoryName/$imageType.${callback.getFileExtension(uri)}"

    fun startUploading() {
        var i = 0

        if (queue.isEmpty()) {
            callback.completed(successList, failureList)
            return
        }

        while (i < maxActive && queue.isNotEmpty()) {
            addToRunningQueue()
            i++
        }
    }

    private fun addToRunningQueue() {
        val uri = queue.poll()!!
        runningQueue.add(uri)
        uploadImageToCloudStorage(uri)
    }

    private fun uploadImageToCloudStorage(locationUri: Uri) {
        val sRef: StorageReference = FirebaseStorage.getInstance().getReference(getLocation(locationUri))

        sRef.putFile(locationUri)
            .addOnSuccessListener { taskSnapshot ->
                taskSnapshot.metadata!!.reference!!.downloadUrl
                    .addOnSuccessListener { uri ->
                        successList.add(uri)
                        runningQueue.remove(locationUri)
                    }
            }
            .addOnFailureListener {
                failureList.add(locationUri)
                runningQueue.remove(locationUri)
            }
    }
}

由于您的需要需要使用线程,所以为了防止竞争条件,我不得不使用 Collections.synchronizedList。要使用它,您需要在 activity 中实现 QueueSyncCallback 并将其作为对 QueueSync 的引用传递。如果要以任何方式访问视图,请确保 completed 中编写的任何代码都包含在 runOnMainThread 中,因为 completed 不会 运行 在主线程上我所知。这应该可行,但我无法对其进行测试,因为它基于您当前的代码。

编辑:-编辑后回复

override fun completed(successList: MutableList<Uri>, failureList: MutableList<Uri>) {
    imageUploadSuccess(successList)
    hideProgressDialog()
}

override fun getFileExtension(uri: Uri): String {
    Constants.getFileExtension(this, imageFileURI[i])
}