android - 在(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 循环执行,直到我们得到onResourceReady
Glide 的响应?也许使用suspendCoroutine
?如果是这样,怎么做?
提前感谢您的帮助。
解决方案
推荐阅读
- python - heroku 中 webhook telegrambot 和烧瓶的问题
- powershell - 从 Invoke-Command 执行嵌套的 ScriptBlock 时出错
- azure - 有没有办法部署不在主文件中的 Azure 资源模块?
- python - 在波浪上旋转一个矩形
- python-3.x - 可以使用什么库或框架来解析 Python 文件并提取基类以及其中的方法
- c# - 使用 appsettings.json 更改 SeriLog 中的最低日志记录级别
- perforce - 如何在当前 CL 中从父级到子级进行 p4 合并?
- html - 在材料手风琴中重新加载数据源后保持展开的行状态
- selenium - 测试如何在某些错误跟踪工具上获取 post 问题的 aftermethod 中的所有日志步骤
- python - 斐波那契尾递归背后的直觉