Mobile App Performance Optimization - Android & iOS Best Practices
Author: Abdoul Razac TOURE
Published on: January 10, 2026
Why Performance Matters
Mobile users are impatient. A slow app leads to poor reviews, high uninstall rates, and decreased engagement. Performance optimization is not a nice-to-have—it’s essential.
Performance Metrics
- FPS (Frames Per Second): Aim for 60 FPS minimum, 120 FPS on modern devices
- Memory Usage: Monitor heap size and watch for memory leaks
- Battery Consumption: Optimize to extend battery life
- Network Latency: Minimize data transfer and API calls
Android Performance Optimization
1. Memory Management
Detecting Memory Leaks
// Bad: Potential memory leak
class MyActivity : AppCompatActivity() {
companion object {
var instance: MyActivity? = null
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
instance = this // Memory leak!
}
}
// Good: Avoid static references
class MyActivity : AppCompatActivity() {
// Use proper lifecycle management
}Best Practices
- Use
WeakReferencefor temporary object references - Nullify references in
onDestroy() - Use Android Profiler to track memory
- Avoid memory leaks from listeners and callbacks
2. Layout Optimization
// Bad: Deep nesting (layout inflation is slow)
Column {
Column {
Column {
Text("Nested deeply")
}
}
}
// Good: Flat hierarchy
Column {
Text("Flat structure")
}3. LazyColumn Performance
// Efficient list rendering
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(items.size, key = { items[it].id }) { index ->
ItemRow(item = items[index])
}
}4. Image Loading Optimization
// Use Coil or Glide for efficient image loading
AsyncImage(
model = ImageRequest.Builder(context)
.data(url)
.crossfade(true)
.placeholder(R.drawable.placeholder)
.build(),
contentDescription = "Product image",
modifier = Modifier.size(200.dp),
contentScale = ContentScale.Crop
)iOS Performance Optimization
1. Memory Management
Avoiding Reference Cycles
// Bad: Reference cycle
class ViewController: UIViewController {
var closure: (() -> Void)?
func setupClosure() {
closure = {
self.doSomething() // Strong reference cycle!
}
}
}
// Good: Capture list
class ViewController: UIViewController {
var closure: (() -> Void)?
func setupClosure() {
closure = { [weak self] in
self?.doSomething()
}
}
}2. View Hierarchy Optimization
// Bad: Complex view hierarchy
VStack {
VStack {
VStack {
Text("Deep nesting")
}
}
}
// Good: Flat structure
VStack {
Text("Optimized")
}3. Lazy Loading with ScrollView
struct ContentView: View {
@State private var items: [Item] = []
@State private var isLoading = false
var body: some View {
ScrollView {
LazyVStack(spacing: 16) {
ForEach(items) { item in
ItemRow(item: item)
}
}
}
.onAppear {
loadMoreItems()
}
}
private func loadMoreItems() {
// Load items incrementally
}
}4. Image Caching
// Use URLCache for automatic HTTP caching
let config = URLSessionConfiguration.default
config.urlCache = URLCache(
memoryCapacity: 10 * 1024 * 1024,
diskCapacity: 100 * 1024 * 1024,
diskPath: "cached_images"
)
let session = URLSession(configuration: config)Network Performance Optimization
Reduce API Calls
// Bad: Multiple API calls
fun loadData() {
getUser() // 1st call
getPosts() // 2nd call
getComments() // 3rd call
}
// Good: Batch requests
fun loadData() {
getConsolidatedData() // Single call
}Implement Pagination
LazyColumn {
items(userList.size) { index ->
UserItem(user = userList[index])
if (index == userList.size - 1) {
LaunchedEffect(Unit) {
loadMoreUsers()
}
}
}
}Battery Optimization
Location Services
// Bad: Continuous high-accuracy location
val request = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 1000).build()
// Good: Appropriate accuracy and interval
val request = LocationRequest.Builder(Priority.PRIORITY_BALANCED_POWER_ACCURACY, 10000).build()Background Work
// Use WorkManager for background tasks
val workRequest = PeriodicWorkRequestBuilder<SyncWorker>(
15, TimeUnit.MINUTES
).build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"sync_work",
ExistingPeriodicWorkPolicy.KEEP,
workRequest
)Monitoring and Profiling
Android Studio Profiler
- CPU Profiler: Track CPU usage and method traces
- Memory Profiler: Monitor heap, detect leaks
- Network Profiler: Analyze API calls
- Energy Profiler: Battery consumption analysis
Xcode Instruments
- Time Profiler: CPU usage
- Allocations: Memory tracking
- Core Data Tool: Database performance
- Network Link Conditioner: Simulate network conditions
Performance Checklist
- Reduce layout hierarchy depth
- Implement efficient list rendering
- Cache network responses
- Monitor memory leaks
- Optimize image sizes
- Implement pagination
- Use lazy loading
- Profile with native tools
- Test on low-end devices
- Monitor battery impact
Conclusion
Performance optimization is an ongoing process. Regular profiling, testing on real devices, and staying updated with platform best practices ensure your app provides a smooth, responsive experience. Invest time in optimization early—it’s easier to maintain good performance than to fix a slow app.