Slide 1

Slide 1 text

Android Rendering Performance and Tools Performance always matters (unless it does not matter)

Slide 2

Slide 2 text

What is rendering? Component GPU Rasterization Screen CPU Convert / load Polygons Load Textures

Slide 3

Slide 3 text

GPU - Rasterization ● Strings, components (Buttons, RadioButton, Checkbox, etc), shapes -> to pixels ● GPU is high consuming process ● Display list: works as a cache strategy for the instances loaded in the gpu. ● Calling invalidate makes this process more expensive in terms of performance

Slide 4

Slide 4 text

GPU - Display List ● List of commands to be executed in the GPU ● These commands are saved once they are created GPU Button Valid displayList ? Execute display List yes no Record new display List Alert! Invalidate is called

Slide 5

Slide 5 text

Invalidated vs Non-Invalidated ● Change background ● Change size ● Change text ● Change position in the layout ● When you call invalidate method inside your custom view ● All resources are pre-loaded in the GPU, so any resource used can help to not invalidate the view ● Keeping resources (xml) to handle the changes (shapes for example) ● Use clip to cut unnecessary part of views that are not visible for the user Invalidated called Invalidated not called

Slide 6

Slide 6 text

Rendering phases - Android View Measure Layout Drawing Android View

Slide 7

Slide 7 text

Frames vs rendering (Android Smooth Transitions) 60 frames / second 1000ms / 60 frames = 16.666 ms/frame Removed Frame Removed Frame You have 16ms to: ● Computations and calculations ● Draw views ● Update views ● Animations and transitions ● Give time to GC collect everything that is needed GOOD LUCK !!!

Slide 8

Slide 8 text

How to measure performance ● Overdraw ● GPU profiling tool Developer options Android Studio ● LogCat ● Layout Inspector

Slide 9

Slide 9 text

How we treat rendering issues? ● 1st: treat performance is not an easy task (keep this in mind) ● Possible points to target: ○ Check Overdraw ○ Check which specific stage of rendering is demanding more work ○ Check hierarchy

Slide 10

Slide 10 text

Overdraw ● How many times a view or part of view is being draw on top of another view / group view ● Some overdraw might be expected, but we might be doing more than necessary ● GPU costs are expensive, reducing overdraw might reduce this costs. Developer Options -> Debug GPU overdraw

Slide 11

Slide 11 text

Overdraw - how to fix https://medium.com/androiddevelopers/draw-what-you-see-a nd-clip-the-e11-out-of-the-rest-6df58c47873e ● Reduce unnecessary backgrounds ● Flatten hierarchy ● Clip to reduce views overlapping ● Eliminate invisible views (if possible) ● Reduce transparency https://www.lvguowei.me/post/android-custom-view-102-3/ https://developer.android.com/codelabs/advanced-android-kotlin-training-clipping-canvas-objects

Slide 12

Slide 12 text

GPU Profiling tool 16ms limit

Slide 13

Slide 13 text

GPU Profiling tool 1 2 3 4 5 6 7 8 Reduce draw logics Reduce draw work Too large / too many images Use Glide/Picasso Reduce hierarchy of views Check animators Reduce work / extract to another thread (onclick(), onLongClick(), onFocusChange(, onKeyListener() Reduce hierarchy of views

Slide 14

Slide 14 text

Layout inspector - Android views Levels of hierarchy

Slide 15

Slide 15 text

Logcat Filter name What does Example TaskActivityManager Show the activity startup time Displayed com.paulacr.performance/androidx.compose.ui. tooling.PreviewActivity: +1s192ms Choreographer Show skipped frames Skipped 42 frames! The application may be doing too much work on its main thread. OpenGLRenderer Time consumption in GPU rendering Davey! duration=743ms; Flags=0, IntendedVsync=151198870863899, Vsync=151199570863871, (...) GpuCompleted=0,

Slide 16

Slide 16 text

Rendering performance for Compose Extracted from https://developers.android.com/ ● Not having xml does not mean that rendering problems ended ● One of the problems for compose is the recomposition

Slide 17

Slide 17 text

Recomposition Tree skipped skipped skipped skipped skipped ● Any composable function has the ability to be re-invoked at anytime ● Composable functions are re-invoked when the input changes ● When recomposition happens it only calls the composables or lambdas that changed and skip the rest

Slide 18

Slide 18 text

Layout inspector - Compose ● Show recomposition count ● Show skipped count ● Allow to view the hierarchy in a better way ● Can tell us where is a potential problem in our composable functions Skipped count Recomposition count

Slide 19

Slide 19 text

Recomposition Compose attributes for functions Skippable: skip the function if all parameters are equal as before Restartable: restarting point Attributes for object instances Immutable Unstable Stable

Slide 20

Slide 20 text

Stable vs Unstable type Stable type ● Marked with annotation @Stable ● Data classes with all “val” properties ● Compose MutableState Unstable type ● Mutable properties (var) ● Collections: List, Set, Map, etc ● Types from third parties libraries ● All classes in non-compose project modules

Slide 21

Slide 21 text

Composable metrics by Chris Banes subprojects { tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { kotlinOptions { if (project.findProperty("app.enableComposeCompilerReports") == "true") { freeCompilerArgs += [ "-P", "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + project.buildDir.absolutePath + "/compose_metrics" ] freeCompilerArgs += [ "-P", "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + project.buildDir.absolutePath + "/compose_metrics" ] } } } } ./gradlew assembleRelease -Papp.enableComposeCompilerReports=true build.gradle (root)

Slide 22

Slide 22 text

Composable metrics { "skippableComposables": 57, "restartableComposables": 63, "readonlyComposables": 0, "totalComposables": 63, "restartGroups": 63, "totalGroups": 67, "staticArguments": 34, … } app-release-module.json restartable skippable scheme("...") fun CatItemImmutable( stable cat: CatImmutable stable buttonText: String stable onClick: Function0 stable onItemClick: Function0 ) app-release-composables.txt Skippability

Slide 23

Slide 23 text

Composable metrics stable class CatImmutable { stable val breed: String stable val color: Color stable val id: Int? = Stable } unstable class CatMutable { stable val breed: String stable var color: Color = Unstable } stability app-release-classes.txt app-release-classes.txt

Slide 24

Slide 24 text

Changing stability @Stable data class CatMutable( val breed: String, @Stable var color: Color ) stable class CatMutable { stable val breed:String stable var color: Color }

Slide 25

Slide 25 text

Lazy Layout Keys LazyColumn { items( items = notes, key = { note -> note.id} ) { note: Note -> NoteItem(item = note) { notes.remove(note) } } }

Slide 26

Slide 26 text

Lazy Layout Keys Without key With key

Slide 27

Slide 27 text

Lambda Modifiers Column { Card( modifier = Modifier.offset(position) ) { Text() } Button() }

Slide 28

Slide 28 text

Lambda Modifiers Column { Card( modifier = Modifier.offset{ position } ) { Text() } Button() }

Slide 29

Slide 29 text

DerivedStateOf ● Used when the state change more than you want to update the UI val isValid = remember { derivedStateOf { typedEmail.value.contains("@") } }

Slide 30

Slide 30 text

Useful references ● Overdraw + GPU ○ https://developer.android.com/topic/performance/rendering/inspect-gpu-rendering ○ https://chris.banes.me/posts/composable-metrics/ ○ https://youtu.be/zdQRIYOST64 (Google Io - how Android renders) ○ https://developer.android.com/topic/performance/rendering/overdraw ○ https://developer.android.com/topic/performance/rendering/inspect-gpu-rendering ● Clip Android Views ○ https://medium.com/androiddevelopers/draw-what-you-see-and-clip-the-e11-out-of-the-r est-6df58c47873e ○ https://www.lvguowei.me/post/android-custom-view-102-3/ ○ https://developer.android.com/codelabs/advanced-android-kotlin-training-clipping-canvas -objects ● Compose ○ https://developer.android.com/jetpack/compose/performance/bestpractices ○ https://youtu.be/6BRlI5zfCCk (compose runtime) ○ https://youtu.be/ahXLwg2JYpc (compose performance tips) ○ https://youtu.be/0yK7KoruhSM (compose rendering phases) ○ https://youtu.be/BjGX2RftXsU (compose modifier deep dive) ○ https://developer.android.com/jetpack/compose/graphics/images/optimization (images)