I have a simple customView that draw a single line as below.
class ViewCustom @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0)
: View(context, attrs, defStyleAttr) {
private val strokePaint = Paint()
.apply { color = Color.BLACK}
.apply { strokeWidth = 6f }
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawLine(
0f, 0f,
width.toFloat(), height.toFloat(),
strokePaint
)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val desiredWidth = suggestedMinimumWidth + paddingLeft + paddingRight
val desiredHeight = suggestedMinimumHeight + paddingTop + paddingBottom
setMeasuredDimension(resolveSize(desiredWidth, widthMeasureSpec),
resolveSize(desiredHeight, heightMeasureSpec))
}
}
It works fine, draw the diagonal line end to end.
However, if I add a coroutine thread around it
class ViewCustom @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0)
: View(context, attrs, defStyleAttr) {
private val treeDrawing by lazy {
TreeDrawingCanvasCustom()
}
private val strokePaint = Paint()
.apply { color = Color.BLACK}
.apply { strokeWidth = 6f }
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
CoroutineScope(Dispatchers.Default).launch { // <-- add coroutine
canvas.drawLine(
0f, 0f,
width.toFloat(), height.toFloat(),
strokePaint
)
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val desiredWidth = suggestedMinimumWidth + paddingLeft + paddingRight
val desiredHeight = suggestedMinimumHeight + paddingTop + paddingBottom
setMeasuredDimension(resolveSize(desiredWidth, widthMeasureSpec),
resolveSize(desiredHeight, heightMeasureSpec))
}
}
It still draws, but at a strange location as shown in the diagram below. I have checked that the height
and width
value is still the same with or without the coroutine.
Why is it behaving as such?
Just found out the reason is that there's only one canvas shared across all drawings. When the onDraw is on the background thread, there's no guarantee others are also manipulating the main thread in drawing the canvas, hence such concurrent drawing will cause the drawing coordinate to be misaligned from its original coordinate.
In the image diagram case below, the drawing is on the Caption area, is because that happens concurrently between the Text Caption drawing, hence it is drawn on the Text Caption area.