Kotlin 协程运行阻塞未按预期工作并且无法阻止 for 循环的执行

R.C*_*der 2 kotlin kotlin-coroutines

在我的应用程序中,我正在执行两个 for 循环,但是这些 for 循环需要按顺序安排,这里是用例:

有两个 for 循环: 1- ImageStickerslist 2-TextStickerslist

我想要做的是在 imagestickerslist 之后,如果正确完成,那么 textstickerslist 才会被执行。

这里的 imagesticker 列表由 url 路径组成,用于从 glide 加载图像,但是如果这些图像具有高分辨率,即使图像尚未从 url 加载,它最终也会使线程继续。为了解决这个问题,尝试添加阻塞调用以在ready和full方法上滑动,但事实证明它没有任何帮助。我很困惑阻塞调用是如何工作的,任何帮助都会非常感激。

这是我执行 for 循环的代码:

 runBlocking {
                            launch {
                                imagestickers.forEach {
                                    runBlocking {
                                        var image = it.path
                                        var x = it.x
                                        var y = it.y
                                        image!!.log()
                                        setimagestickers(image!!, x!!, y!!, it.width!!, it.height!!)
                                    }
                                }
                            }.join()
                            textstickers.forEach {
                                runBlocking {
                                    var text = it.text.toString()
                                    var color = it.color
                                    var font = it.font
                                    var size = it.size
                                    var x = it.x
                                    var y = it.y
                                    setTextSticker(text, Color.parseColor(color), size!!, x!!, y!!)
                                }
                            }
                        }
Run Code Online (Sandbox Code Playgroud)

这是我进行主要计算的两种方法:

 fun setimagestickers(path:String,x:Int,y:Int,w:Int,h:Int){

           Glide.with(this@NewStickerActivity).asBitmap().timeout(6000000).load(path).into(object : CustomTarget<Bitmap>() {
               override fun onLoadCleared(placeholder: Drawable?) {

               }

               override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
                   var size: ViewGroup.LayoutParams
                   var bmp1 = resource
                   size = UiHelper.getHeightWidth(this@NewStickerActivity, (w).toInt(), (h).toInt())
                   var resizedBitmap = Bitmap.createScaledBitmap(bmp1, size.width, size.height, false)
                   var drawable = BitmapDrawable(resources, resizedBitmap)
                   var dsImageSticker = DrawableSticker(drawable)
                   dsImageSticker.setTag("ImageSticker")
                   var pm: List<Int>
                   if (density > 3.0) {
                       pm = UiHelper.getmargins(this@NewStickerActivity, (x).toInt(), (y).toInt())
                   } else {
                       pm = UiHelper.getmargins(this@NewStickerActivity, (x).toInt(), (y).toInt())
                   }
                   Log.i("Hmmm:", pm.get(0).toFloat().toString() + "::" + pm.get(1).toFloat().toString())

                   stickerView.addStickerAndSetMatrix1(
                           dsImageSticker,
                           pm.get(0).toFloat(),
                           pm.get(1).toFloat()
                   )

               }

           })
    }
   fun setTextSticker(text: String, color: Int,size: Int, x: Int, y: Int){
            val bmp1: Bitmap
            val drawable: Drawable
            var l: List<Int>
            if (density > 3.0) {
                l = UiHelper.getmargins(this@NewStickerActivity, (x).toInt(), (y * 1.07).toInt())
            } else {
                l = UiHelper.getmargins(this@NewStickerActivity, x.toInt(), y.toInt())
            }
            //var tf = Typeface.createFromFile(assets,"fonts/"+path)
            var tf = Typeface.createFromAsset(assets, "fonts/Myriad Pro Bold SemiExtended.ttf")
            bmp1 = createBitmapFromLayoutWithText(this@NewStickerActivity, size, text, color, 0f, tf, 0f, 0f, color, Gravity.LEFT)
            drawable = BitmapDrawable(resources, bmp1)
            var dsTextSticker = DrawableSticker(drawable)
            dsTextSticker.setTag("textSticker")
            Log.i("Hmmm:", l.get(0).toFloat().toString() + "::" + l.get(1).toFloat().toString())
            /*if (rotate) {
                stic.addStickerAndSetrotate(
                        dsTextSticker, rotationdegress,
                        l.get(0).toFloat(),
                        l.get(1).toFloat()
                )
            } else {*/
            stickerView.addStickerAndSetMatrix1(
                    dsTextSticker,
                    l.get(0).toFloat(),
                    l.get(1).toFloat())



    }
Run Code Online (Sandbox Code Playgroud)

更新

我通过按顺序递增和获取图像,在没有协程的情况下完成了这项工作:首先,我获取了一个 Int,然后不断递增,直到达到列表大小,这是我的代码:首先,我这样做了:

var i = 0 
setimagestickers(imagestickers.get(i).path!!, imagestickers.get(i).x!!, imagestickers.get(i).y!!, imagestickers.get(i).width!!, imagestickers.get(i).height!!)
Run Code Online (Sandbox Code Playgroud)

之后,在资源准备就绪后,就成功了!

Glide.with(this@NewStickerActivity).asBitmap().timeout(6000000).load(path).into(object : CustomTarget<Bitmap>() {
               override fun onLoadCleared(placeholder: Drawable?) {

               }

               override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
                   var size: ViewGroup.LayoutParams
                   var bmp1 = resource
                   size = UiHelper.getHeightWidth(this@NewStickerActivity, (w).toInt(), (h).toInt())
                   var resizedBitmap = Bitmap.createScaledBitmap(bmp1, size.width, size.height, false)
                   var drawable = BitmapDrawable(resources, resizedBitmap)
                   var dsImageSticker = DrawableSticker(drawable)
                   dsImageSticker.setTag("ImageSticker")
                   var pm: List<Int>
                   if (density > 3.0) {
                       pm = UiHelper.getmargins(this@NewStickerActivity, (x).toInt(), (y).toInt())
                   } else {
                       pm = UiHelper.getmargins(this@NewStickerActivity, (x).toInt(), (y).toInt())
                   }
                   Log.i("Hmmm:", pm.get(0).toFloat().toString() + "::" + pm.get(1).toFloat().toString())

                   stickerView.addStickerAndSetMatrix1(
                           dsImageSticker,
                           pm.get(0).toFloat(),
                           pm.get(1).toFloat()
                   )
                i++
                if(i < imagestickers.size){
                    setimagestickers(imagestickers.get(i).path!!, imagestickers.get(i).x!!, imagestickers.get(i).y!!, imagestickers.get(i).width!!, imagestickers.get(i).height!!)
                }
                   else{
                    if(textstickers.isNullOrEmpty()){
                        loader!!.hide()
                    }
                    else {
                        setTextSticker(textstickers.get(j).text!!, Color.parseColor(textstickers.get(j).color), textstickers.get(j).size!!, textstickers.get(j).x!!, textstickers.get(j).y!!)
                    }
                    }
               }

           })
Run Code Online (Sandbox Code Playgroud)

但是我仍然想知道如何使用协程而不是这种方法来解决它!

Mar*_*nik 5

基本上,您正在进行异步 Glide 调用,而无需暂停协程,直到它们完成为止。您必须更改的第一件事是引入suspend fun getImageSticker()

suspend fun getSticker(path: String): Bitmap =
    suspendCancellableCoroutine { continuation -> Glide
        .with(this@NewStickerActivity)
        .asBitmap()
        .timeout(6000000)
        .load(path)
        .into(object : CustomTarget<Bitmap>() {
            override fun onResourceReady(resource: Bitmap, x: Transition<in Bitmap>?) {
                continuation.resume(resource)
            }
        })
    }
Run Code Online (Sandbox Code Playgroud)

请注意,这会返回一个Bitmap. 现在您可以像调用常规阻塞函数一样调用它,并从调用方使用其结果:

suspend fun setimagestickers(path: String, x: Int, y: Int, w: Int, h: Int) {
    val resource = getSticker(path)
    var size: ViewGroup.LayoutParams
    var bmp1 = resource
    size = UiHelper.getHeightWidth(this@NewStickerActivity, (w).toInt(), (h).toInt())
    var resizedBitmap = Bitmap.createScaledBitmap(bmp1, size.width, size.height, false)

}
Run Code Online (Sandbox Code Playgroud)

现在,如果您想并行调用setimagestickers,请在循环中启动它们:

launch {
    imagestickers.map {
        launch {
            var image = it.path
            var x = it.x
            var y = it.y
            image!!.log()
            setimagestickers(image!!, x!!, y!!, it.width!!, it.height!!)
        }
    }.joinAll()
    textstickers.forEach {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)