ESC
Type to search guides, tutorials, and reference documentation.
Verified by Garnet Grid

Mobile App Performance

Optimize mobile application performance for speed, responsiveness, and battery life. Covers startup time, rendering performance, memory management, network optimization, battery impact, and the patterns that make mobile apps feel instant.

Mobile performance is unforgiving. Users abandon apps that take more than 3 seconds to launch, scroll jank is immediately noticeable, and battery drain gets your app uninstalled. Unlike web performance where you optimize for Core Web Vitals, mobile performance requires optimizing for CPU-constrained devices, limited memory, variable network conditions, and battery life.


Startup Time Optimization

App Launch Phases:
  1. Process creation (OS-level, unavoidable)
  2. Runtime initialization
  3. Application initialization
  4. First frame rendered ← User sees content

Cold Start Targets:
  Excellent: < 1 second
  Good: 1-2 seconds
  Poor: > 2 seconds

Optimization Strategies:
  ☐ Defer non-critical initialization
  ☐ Lazy-load modules not needed on first screen
  ☐ Cache first screen data locally
  ☐ Show skeleton UI immediately
  ☐ Reduce dependency injection graph
  ☐ Pre-warm data in background after launch

iOS Startup

// Measure app launch time
class AppDelegate: UIResponder, UIApplicationDelegate {
    let launchStart = CFAbsoluteTimeGetCurrent()
    
    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // CRITICAL: Only essential initialization here
        configureAnalytics()
        configureAuth()
        
        // DEFER: Non-critical initialization
        DispatchQueue.global().async {
            self.configureFeatureFlags()
            self.prefetchData()
            self.initializeSDKs()
        }
        
        let launchTime = CFAbsoluteTimeGetCurrent() - launchStart
        Analytics.track("app_launch", properties: ["duration_ms": launchTime * 1000])
        
        return true
    }
}

// Lazy-load view controllers
class MainTabBarController: UITabBarController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Only create the first tab immediately
        let homeVC = HomeViewController()
        
        // Other tabs lazy-loaded when tapped
        let searchVC = LazyViewController { SearchViewController() }
        let profileVC = LazyViewController { ProfileViewController() }
        
        viewControllers = [homeVC, searchVC, profileVC]
    }
}

Android Startup

// Baseline Profiles: Pre-compile hot paths
// baseline-prof.txt
HSPLcom/app/MainActivity;->onCreate(Landroid/os/Bundle;)V
HSPLcom/app/data/Repository;->getData()Lkotlinx/coroutines/flow/Flow;

// App Startup Library: Control initialization order
class AnalyticsInitializer : Initializer<Analytics> {
    override fun create(context: Context): Analytics {
        return Analytics.init(context)
    }
    
    override fun dependencies(): List<Class<out Initializer<*>>> {
        return emptyList() // No dependencies, can init early
    }
}

class FeatureFlagInitializer : Initializer<FeatureFlags> {
    override fun create(context: Context): FeatureFlags {
        return FeatureFlags.init(context) // Can be async
    }
    
    override fun dependencies(): List<Class<out Initializer<*>>> {
        return listOf(AnalyticsInitializer::class.java)
    }
}

Network Optimization

Strategies:
  1. Cache aggressively
     - Cache API responses
     - Offline-first with background sync
     - Image caching with disk + memory layers

  2. Reduce payload size
     - gzip/brotli compression
     - Pagination and lazy loading
     - GraphQL: request only needed fields
     - Protobuf instead of JSON (30-50% smaller)

  3. Minimize requests
     - Batch API calls
     - Prefetch predictable data
     - Use push (WebSocket) instead of polling

  4. Handle poor connectivity
     - Retry with exponential backoff
     - Show cached data with staleness indicator
     - Queue mutations for later sync

Anti-Patterns

Anti-PatternConsequenceFix
Init everything at launchSlow startup, poor first impressionLazy and deferred initialization
Blocking main threadUI freezes, ANRsOffload work to background threads
No image cachingRepeated downloads, data wasteDisk + memory image cache (SDWebImage, Coil)
Polling for updatesBattery drain, data wastePush notifications, WebSockets
No performance baselineCannot detect regressionsBenchmark tests, performance monitoring

Mobile performance is not an optimization — it is a feature. Users cannot see your architecture, but they can feel your performance.

Jakub Dimitri Rezayev
Jakub Dimitri Rezayev
Founder & Chief Architect • Garnet Grid Consulting

Jakub holds an M.S. in Customer Intelligence & Analytics and a B.S. in Finance & Computer Science from Pace University. With deep expertise spanning D365 F&O, Azure, Power BI, and AI/ML systems, he architects enterprise solutions that bridge legacy systems and modern technology — and has led multi-million dollar ERP implementations for Fortune 500 supply chains.

View Full Profile →