Custom drawing on Canvas can affect your app's frame rate and battery life. Drawing complex shapes or many objects every frame may reduce smoothness below 60fps. Excessive overdraw or inefficient paint operations increase CPU and GPU load, causing higher battery use and possible UI lag.
Custom drawing (Canvas) in Android Kotlin - Build, Publish & Deploy
To keep your app smooth, draw only what changes each frame. Cache static parts in a bitmap to avoid redrawing them repeatedly. Use hardware acceleration and avoid expensive operations like creating new objects inside the onDraw() method. Profile your drawing with Android Studio GPU tools to find bottlenecks.
Custom drawing code itself is small and does not significantly increase app size. However, if you include large bitmap resources or complex vector assets for drawing, these can increase your APK or AAB size and slow startup. Optimize image sizes and use vector drawables when possible.
Android uses Canvas API for custom drawing, typically inside View.onDraw(). iOS uses Core Graphics with draw(_ rect: CGRect) in UIView subclasses. Both platforms support hardware acceleration but differ in APIs and lifecycle. Android requires careful invalidation calls to redraw, while iOS uses setNeedsDisplay(). Understanding these helps when porting custom drawing code.
Ensure your custom drawing does not cause excessive battery drain or app crashes, as these can lead to rejection. Follow Android's Material Design guidelines for visual consistency. Avoid drawing misleading or inappropriate content. Test on multiple devices to ensure performance and visual quality meet Google Play standards.
Likely your custom drawing code is doing heavy work on the main thread during startup, such as decoding large bitmaps or complex drawing without caching. This blocks UI rendering. To fix, move heavy processing off the main thread, cache drawings, and simplify the drawing logic.
Practice
onDraw() method in Android custom views?Solution
Step 1: Understand the role of
TheonDraw()onDraw()method is called when the view needs to display its content.Step 2: Identify what
It uses a Canvas object to draw shapes, text, or images directly on the view.onDraw()usesFinal Answer:
To draw shapes and graphics on the screen using a Canvas -> Option BQuick Check:
onDraw()draws on Canvas [OK]
onDraw() is for drawing only [OK]- Confusing
onDraw()with event handlers - Thinking
onDraw()manages layout - Assuming
onDraw()loads images automatically
Solution
Step 1: Check Paint object creation syntax
In Kotlin, Paint is created with default constructor and properties set via setters or apply block.Step 2: Verify correct property assignments
Usingapplyallows settingcolorandstyleproperly.Final Answer:
val paint = Paint().apply { color = Color.RED; style = Paint.Style.STROKE } -> Option CQuick Check:
Useapplyto set Paint properties [OK]
apply block to set Paint properties cleanly [OK]- Trying to pass parameters to Paint constructor
- Using chained setters that don't exist
- Confusing method calls with property assignments
onDraw() code snippet, what shape will be drawn?
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val paint = Paint().apply { color = Color.BLUE; style = Paint.Style.FILL }
canvas.drawCircle(100f, 100f, 50f, paint)
}Solution
Step 1: Analyze Paint properties
Paint color is blue and style is FILL, so shape will be filled blue.Step 2: Identify Canvas drawing method
drawCircledraws a circle at (100f, 100f) with radius 50f.Final Answer:
A blue filled circle centered at (100, 100) with radius 50 -> Option AQuick Check:
drawCircle+ FILL + blue = filled blue circle [OK]
- Confusing FILL with STROKE style
- Mixing up circle and rectangle drawing methods
- Ignoring Paint color property
onDraw() method:
override fun onDraw(canvas: Canvas) {
val paint = Paint()
paint.color = Color.GREEN
canvas.drawRect(50f, 50f, 150f, 150f)Solution
Step 1: Check drawRect method parameters
ThedrawRectmethod requires a Paint object as the last parameter to know how to draw.Step 2: Identify missing argument
The code callsdrawRectwith only coordinates, missing the Paint parameter.Final Answer:
Missing Paint parameter in drawRect call -> Option AQuick Check:
drawRectneeds Paint argument [OK]
- Forgetting Paint parameter in draw calls
- Thinking Paint color order matters
- Assuming floats are invalid for coordinates
onDraw() implementations achieves this correctly?Solution
Step 1: Understand the requirement
We need a red filled circle with a black stroke border of 5 pixels thickness.Step 2: Check each option's drawing logic
override fun onDraw(canvas: Canvas) { super.onDraw(canvas) val fillPaint = Paint().apply { color = Color.RED; style = Paint.Style.FILL } val strokePaint = Paint().apply { color = Color.BLACK; style = Paint.Style.STROKE; strokeWidth = 5f } canvas.drawCircle(100f, 100f, 50f, fillPaint) canvas.drawCircle(100f, 100f, 50f, strokePaint) } draws the filled circle first, then draws the stroke circle on top with correct colors and stroke width.Step 3: Identify why others fail
override fun onDraw(canvas: Canvas) { super.onDraw(canvas) val paint = Paint().apply { color = Color.RED; style = Paint.Style.STROKE; strokeWidth = 5f } canvas.drawCircle(100f, 100f, 50f, paint) } only draws a red stroke, no fill. override fun onDraw(canvas: Canvas) { super.onDraw(canvas) val paint = Paint().apply { color = Color.BLACK; style = Paint.Style.FILL } canvas.drawCircle(100f, 100f, 50f, paint) } draws a black filled circle only. override fun onDraw(canvas: Canvas) { super.onDraw(canvas) val paint = Paint().apply { color = Color.RED; style = Paint.Style.FILL; strokeWidth = 5f } canvas.drawCircle(100f, 100f, 50f, paint) } sets strokeWidth but style is FILL, so no stroke border.Final Answer:
Uses two Paint objects: red FILL then black STROKE with 5f width -> Option DQuick Check:
Draw fill then stroke with separate Paints [OK]
- Using strokeWidth with FILL style only
- Drawing stroke before fill causing overlap issues
- Using one Paint for both fill and stroke
Ready to prove it?
Pass the test and this pattern moves unknown
