首页 > 解决方案 > 在(for循环的)回调响应中同步执行

问题描述

我们正在使用firebase 实时数据库。我们正在一个一个地读取数据。根据数据,我们需要从画布上的 URL 创建位图,然后继续在该位图/画布上绘制其他内容。然而,使用 Glide 从画布上的 url 绘制位图是一个异步过程,因此,在我们拥有带有位图的 Canvas 之前,我们已经向前推进了。所以,它给了空画布。

下面是代码:

private fun saveBoardPages() {
        
        databaseReference.child("data").addListenerForSingleValueEvent(object : ValueEventListener {
            override fun onDataChange(snapshot: DataSnapshot) {
             
                
                val document = PdfDocument()

                var pageNumber = 1

                for (pageData in snapshot.children) {

                    // comment by srdpatel: 3/25/2021 We want to save only selected pages.
                    if (pageData.key == null) {
                        continue
                    }

                    // comment by srdpatel: 3/25/2021 If the format of the key gets changed, we will get exception
                    if (!selectedBoards.contains(pageData.key?.toInt())) {
                        continue
                    }

                    // TODO by srdpatel: 3/26/2021 We need to have proper size of the pdf page for proper alignment
                    // comment by srdpatel: 3/25/2021 info part that contains orientation details
                    pageData.child("info").getValue<PageInfo>()?.let {
                        ScreenUtils.getScreenSize(this@BoardActivity)
                        val pageInfo = if (it.orientation == ORIENTATION_PORTRAIT) {
                            PdfDocument.PageInfo.Builder(
                                MathUtils.percentageOf(82.96F, StaticConstants.screenWidth).toInt(),
                                MathUtils.percentageOf(74.6875F, StaticConstants.screenHeight)
                                    .toInt(),
                                pageNumber++
                            ).create()
                        } else {
                            PdfDocument.PageInfo.Builder(
                                PDF_WIDTH_LANDSCAPE,
                                PDF_HEIGHT_LANDSCAPE,
                                pageNumber++
                            ).create()
                        }


                        //region Set new data on the canvas
                        val page = document.startPage(pageInfo)
                        // comment by srdpatel: 03/23/2021 Gives everything that is currently visible
                        var canvas = page.canvas
                        //endregion

                        when (it.backGround) {
                            BackGround.PDF -> {
                                
                                // TODO by srdpatel: 3/26/2021 If it is a pdf, it will have an image and we need to render it first on pdf page
                                // TODO by srdpatel: 3/28/2021 Empty because it is an asynchronous process!!
                                //  Before it can draw the bitmap, we have already moved ahead with empty canvas!!
                                canvas = drawBitmapOnCanvas(canvas, it)

                            }
                            BackGround.IMAGE -> {
                            }
                            BackGround.COLOR -> {
                                canvas.drawColor(Color.parseColor(it.color))
                            }
                            BackGround.GRAPH_RED ->
                                drawBackgroundToCanvas(R.drawable.graph_red, canvas, it.orientation)
                            BackGround.GRAPH_BLUE -> drawBackgroundToCanvas(
                                R.drawable.graph_blue,
                                canvas,
                                it.orientation
                            )
                            BackGround.LINES -> drawBackgroundToCanvas(
                                R.drawable.rules,
                                canvas,
                                it.orientation
                            )
                            BackGround.DOTS -> drawBackgroundToCanvas(
                                R.drawable.dots,
                                canvas,
                                it.orientation
                            )
                        }

                        // comment by srdpatel: 03/23/2021 If we have inserted an image, we will fall here: BoardSketch.
                        // It is data inside data in firebase database
                        for (dataChild in pageData.child("data").children) {
                            dataChild.getValue<BoardSketch>()?.let { sketchData ->


                                when (sketchData.shape) {
                                    // TODO by srdpatel: 3/28/2021 Need to manage orientation and size (width and height)
                                    Shape.IMAGE -> drawBitmapOnCanvas(
                                        canvas,
                                        sketchData.data,
                                        sketchData
                                    )
//                                Shape.TEXT -> addTextToBoardWindow(key)
                                    else -> {
                                        val points = ArrayList<Pair<Float, Float>>()
                                        sketchData.data.split("$").forEach {

                                            val data = it.split("#")
                                            if (data.size == 2) {
                                                try {
                                                    points += Pair(
                                                        data[0].toFloat(),
                                                        data[1].toFloat()
                                                    )
                                                } catch (e: Exception) {
                                                    Timber.d(" :$LOG_APP_NAME: BoardActivity: saveBoardPages: sketchData: :onDataChange: $e")
                                                }
                                            }

                                        }
                                        if (points.isNotEmpty()) {
                                            drawToCanvas(points, sketchData.copy().apply {
                                                stroke = viewModel.getDeviceStroke(stroke)
                                            }, canvas)
                                        }
                                    }
                                }

                            }
                        }
                        document.finishPage(page)

                    }
                }

                createPDFFile().let { file ->
                    FileOutputStream(file).use {
                        document.writeTo(it)
                        it.flush()
                    }
                    val uri =
                        FileProvider.getUriForFile(this@BoardActivity, Constants.authority, file)

                    Utils.saveDocumentToGDrive(uri, this@BoardActivity)
                }
            }

            override fun onCancelled(error: DatabaseError) {
                Timber.d(" :$LOG_APP_NAME: BoardActivity: saveBoardPages: :onCancelled: $error")
            }
        })
    }

画布 = drawBitmapOnCanvas(画布,它)

private fun drawBitmapOnCanvas(canvas: Canvas, pageInfo: PageInfo): Canvas {
        return drawBitmapOnCanvas(canvas, pageInfo.storagePath)
    }

drawBitmapOnCanvas(画布,pageInfo.storagePath)

private fun drawBitmapOnCanvas(canvas: Canvas, uriStringPath: String?): Canvas {
        if (uriStringPath == null) return canvas
        var tempCanvas = canvas
        // TODO by srdpatel: 3/28/2021 We need the same size and attributes of pdf_view.
        ScreenUtils.getScreenSize(this)
        pdfViewWidthPortrait = MathUtils.percentageOf(82.96F, StaticConstants.screenWidth).toInt()
        pdfViewHeightPortrait = MathUtils.percentageOf(74.6875F, StaticConstants.screenHeight).toInt()

        Glide.with(this)
            .asBitmap()
            .override(pdfViewWidthPortrait, pdfViewHeightPortrait)
            .fitCenter()
            .load(uriStringPath)
            .into(object : CustomTarget<Bitmap>() {
                override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
                    tempCanvas = Canvas(resource)
                }

                override fun onLoadCleared(placeholder: Drawable?) {
                    // this is called when imageView is cleared on lifecycle call or for
                    // some other reason.
                    // if you are referencing the bitmap somewhere else too other than this imageView
                    // clear it here as you can no longer have the bitmap
                }
            })
        return tempCanvas
    }

目标是:根据 firebase 实时数据库返回的数据(文本、图像、绘图、注释等)创建一个 pdf 文件(我们正在使用画布和 PdfDocument)。

是否有一种coroutine(或任何其他)方法可以阻止回调下的 for 循环执行,直到我们得到onResourceReadyGlide 的响应?也许使用suspendCoroutine?如果是这样,怎么做?

提前感谢您的帮助。

标签: androidkotlinkotlin-coroutines

解决方案


推荐阅读