Performance Optimizations
This guide covers various performance optimization features available in the project.
Compose Compiler Metrics
The project includes built-in support for Compose compiler metrics to help optimize your composables.
Check the gradle.properties
file to ensure the following:
This configuration will generate detailed reports in:
build/<module>/compose-metrics
: Composition metricsbuild/<module>/compose-reports
: Compiler reports
Using the Reports
- Skippability Report: Shows which composables can't skip recomposition
- Events Report: Details composition events
- Metrics Report: Performance metrics for each composable
Optimizing Composables
Use the reports to identify and fix recomposition issues:
// Bad: Class not marked as stable
data class UiState(
val mutableList: MutableList<String> // Unstable type
)
// Good: Stable class with immutable properties
@Immutable
data class UiState(
val list: List<String> // Immutable type
)
Common optimizations:
// Mark data classes as stable
@Stable
data class YourData(...)
// Use immutable collections
val items: ImmutableList<Item>
// Remember expensive computations
val filteredList = remember(items) {
items.filter { ... }
}
Tip
Use @Immutable
for classes that never change and @Stable
for classes whose properties may
change but maintain identity.
R8 and ProGuard Optimization
Project Structure for Obfuscation
The project follows a consistent pattern for data models to simplify ProGuard/R8 rules:
├── feature/
│ └── your-feature/
│ └── model/ // Models kept unobfuscated
└── core/
└── network/
└── model/ // Data models kept unobfuscated
ProGuard and Consumer Rules
If your app works in debug
build but not in release
build that typically indicates obfuscation
issues. In that case you need to add or edit the proguard rules. These can be found in
# Keep all models
-keep class **.model.** { *; }
# Keep Kotlinx Serialization
-keepattributes *Annotation*, InnerClasses
-dontnote kotlinx.serialization.AnnotationsKt
Note
The project's model organization makes it easy to keep data models unobfuscated while allowing safe obfuscation of implementation classes.
Gradle Build Optimization
Build Scan
The project includes Gradle Enterprise build scan support:
// settings.gradle.kts
plugins {
id("com.gradle.develocity") version ("3.19.1")
}
develocity {
buildScan {
publishing.onlyIf { !System.getenv("CI").isNullOrEmpty() }
termsOfUseUrl.set("https://gradle.com/help/legal-terms-of-use")
termsOfUseAgree.set("yes")
}
}
Use build scans to:
- Identify slow tasks
- Find configuration issues
- Optimize dependency resolution
Multi-Module Build Optimization
Take advantage of the project's modular structure:
-
Make Module: Instead of rebuilding the entire project, use Make Module:
- Android Studio: Right-click module → Make Module
- Command Line:
./gradlew :module:name:assembleDebug
-
Parallel Execution: Enabled in
gradle.properties
: -
Configuration Caching: Already enabled for supported tasks
Tip
When working on a feature, use Make Module on just that feature's module to significantly reduce build time.
Baseline Profiles
Note
Baseline profile support is coming soon to improve app startup performance.
Planned Implementation
// build.gradle.kts
androidApplication {
baselineProfile {
automaticGenerationDuringBuild = true
}
}
This will include:
- Startup trace collection
- Critical user path optimization
- Ahead-of-time compilation for key paths
Firebase Performance Monitoring
This template includes Firebase Performance Monitoring setup through the Firebase convention plugin:
// FirebaseConventionPlugin.kt
class FirebaseConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("com.google.firebase.firebase-perf")
}
dependencies {
"implementation"(libs.findLibrary("firebase.perf").get())
}
}
}
}
This gives you automatic monitoring of:
- Network requests
- App startup time
- Screen render time
- Frozen frames
You can also add custom traces:
FirebasePerformance.getInstance().newTrace("custom_operation").apply {
start()
// Your code here
stop()
}
Tip
Use the Firebase Console to view performance metrics and identify bottlenecks in your app.
Additional Performance Tips
-
Image Loading:
-
List Performance:
-
State Hoisting:
-
Navigation Performance:
Important
Always profile your app's performance using Android Studio's CPU Profiler and Layout Inspector before and after optimizations to ensure they're effective.
Further Reading
- Useful Tips & Tricks: Get useful tips for development and debugging
- CI/CD Setup: Set up continuous integration and deployment for the project
- Publishing to Play Store: Learn how to publish your app to the Google Play Store