skip to Main Content

when ever I build my project I got this error

here is the kotlin class code

var textBitmap: Bitmap? = null
dynamicItem.dynamicText[imageKey]?.let { drawingText ->
            dynamicItem.dynamicTextPaint[imageKey]?.let { drawingTextPaint ->
drawTextCache[imageKey]?.let {
                    textBitmap = it
                } ?: kotlin.run {
                    textBitmap = Bitmap.createBitmap(drawingBitmap.width, drawingBitmap.height, Bitmap.Config.ARGB_8888)
                    val drawRect = Rect(0, 0, drawingBitmap.width, drawingBitmap.height)
                    val textCanvas = Canvas(textBitmap)
                    drawingTextPaint.isAntiAlias = true
                    val fontMetrics = drawingTextPaint.getFontMetrics();
                    val top = fontMetrics.top
                    val bottom = fontMetrics.bottom
                    val baseLineY = drawRect.centerY() - top / 2 - bottom / 2
                    textCanvas.drawText(drawingText, drawRect.centerX().toFloat(), baseLineY, drawingTextPaint);
                    drawTextCache.put(imageKey, textBitmap as Bitmap)
                }

I couldn’t figure out how to fix it

2

Answers


  1. Instead of doing nested let like that, i would prefer to do some guard clause

    val drawingText = dynamicItem.dynamicText[imageKey] ?: return // or you could assign an empty string `?: "" `
    val drawingTextPaint = dynamicItem.dynamicTextPaint[imageKey] ?: return
    val textBitmap: Bitmap = drawTextCache[imageKey] ?: Bitmap.createBitmap(drawingBitmap.width, drawingBitmap.height, Bitmap.Config.ARGB_8888).applyCanvas {
       val drawRect = Rect(0, 0, drawingBitmap.width, drawingBitmap.height)
       val fontMetrics = drawingTextPaint.getFontMetrics()
       val top = fontMetrics.top
       val bottom = fontMetrics.bottom
       val baseLineY = drawRect.centerY() - top / 2 - bottom / 2
       drawingTextPaint.isAntiAlias = true
       drawText(drawingText, drawRect.centerX().toFloat(), baseLineY, drawingTextPaint);
    }
    drawTextCache.put(imageKey, textBitmap)
    
    Login or Signup to reply.
  2. Basically Kotlin can’t smart cast textBitmap to a non-null Bitmap inside that lambda. You’re probably getting the error on the Canvas(textBitmap) call, which can’t take a null parameter, and the compiler can’t guarantee textBitmap isn’t null at that moment.

    It’s a limitation of lambdas referencing external vars which can be changed – I think it’s because a lambda could potentially be run at some other time, so no guarantees can be made about what’s happening to that external variable and whether something else could have modified it. I don’t know the details, there’s some chat here if you like.

    The fix is pretty easy though, if all you’re doing is creating a textBitmap variable and assigning something to it:

    // Assign it as a result of the expression - no need to create a var first and keep
    // changing the value, no need for a temporary null value, it can just be a val
    val textBitmap: Bitmap? =
        dynamicItem.dynamicText[imageKey]?.let { drawingText ->
            dynamicItem.dynamicTextPaint[imageKey]?.let { drawingTextPaint ->
                drawTextCache[imageKey]
                ?: Bitmap.createBitmap(drawingBitmap.width, drawingBitmap.height, Bitmap.Config.ARGB_8888).apply {
                        val drawRect = Rect(0, 0, drawingBitmap.width, drawingBitmap.height)
                        val textCanvas = Canvas(this)
                        drawingTextPaint.isAntiAlias = true
                        val fontMetrics = drawingTextPaint.getFontMetrics();
                        val top = fontMetrics.top
                        val bottom = fontMetrics.bottom
                        val baseLineY = drawRect.centerY() - top / 2 - bottom / 2
                        textCanvas.drawText(drawingText, drawRect.centerX().toFloat(), baseLineY, drawingTextPaint);
                        drawTextCache.put(imageKey, this)
                }
            }
        }   
    

    I’d recommend breaking the bitmap creation part out into its own function for readability, and personally I’d avoid the nested lets (because it’s not immediately obvious what you get in what situation) but that’s a style choice

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search