Mobile Development

Mobile App Performance Optimization

TOKEN

Optimasi performa aplikasi mobile — memory profiling, rendering, network caching, battery optimization, dan cold start

📋 Daftar Isi
  1. Mengapa Performance Penting
  2. Memory Profiling
  3. Rendering Performance
  4. Network Optimization
  5. Battery Optimization
  6. Cold Start Optimization
  7. Quiz Pemahaman

1. Mengapa Performance Penting?

Performa aplikasi mobile secara langsung memengaruhi user retention, rating di app store, dan konversi bisnis. Studi menunjukkan bahwa penundaan 1 detik dalam loading time dapat menurunkan konversi hingga 7%.

MetrikTargetDampak
Cold Start< 2 detik53% user abandon jika > 3 detik
Frame Rate60 fps (16.6ms/frame)Jank terlihat di bawah 50 fps
Memory< 200 MB (target)OOM crash di device low-end
Battery drain< 5% per jam aktifUser uninstall app boros baterai
Network< 500ms API responseUser percepat app lambat

2. Memory Profiling

Memory leak adalah penyebab utama crash di mobile. Profiling tools membantu mendeteksi alokasi berlebihan dan leak.

Bash — Android Memory Profiling
# Menggunakan Android Studio Profiler
# 1. Buka View > Tool Windows > Profiler
# 2. Pilih device & process
# 3. Click "Memory" row

# Menggunakan adb untuk quick check
adb shell dumpsys meminfo com.myapp

# Output contoh:
# App Summary:
#   Java Heap:    15,234 KB
#   Native Heap:  8,456 KB
#   Code:         12,789 KB
#   Stack:        1,234 KB
#   Graphics:     25,678 KB
#   Total PSS:    63,391 KB

# Memory heap dump
adb shell am dumpheap com.myapp /data/local/tmp/heap.hprof
adb pull /data/local/tmp/heap.hprof

# Analyze dengan Android Studio atau MAT (Memory Analyzer Tool)
Swift — iOS Memory Debugging
// Instruments > Leaks
// Xcode > Debug Memory Graph

// Detect retain cycles
class ViewController: UIViewController {
    var onComplete: (() -> Void)?

    override func viewDidLoad() {
        super.viewDidLoad()
        // ❌ Retain cycle: self -> onComplete -> self
        onComplete = {
            self.view.backgroundColor = .red
        }

        // ✅ Fix: gunakan weak self
        onComplete = { [weak self] in
            self?.view.backgroundColor = .red
        }
    }
}

// Memory warning handler
override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Clear caches
    ImageCache.shared.removeAll()
    URLCache.shared.removeAllCachedResponses()
}

2.1 Common Memory Issues

IssuePenyebabSolusi
Retain CycleCircular referenceweak/unowned reference
Large BitmapLoad gambar tanpa resizeDownsample & cache
Leaked Activity/FragmentCallback ke destroyed viewLifecycle-aware component
Cache overflowTanpa eviction policyLRU cache dengan max size

3. Rendering Performance

Kotlin — RecyclerView Optimization
// ❌ Buruk: inflate baru setiap kali
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val view = LayoutInflater.from(parent.context)
        .inflate(R.layout.item_complex, parent, false)
    return ViewHolder(view)
}

// ✅ Baik: gunakan ListAdapter + DiffUtil
class ItemAdapter : ListAdapter<Item, ItemAdapter.ViewHolder>(DiffCallback()) {

    class DiffCallback : DiffUtil.ItemCallback<Item>() {
        override fun areItemsTheSame(old: Item, new: Item) = old.id == new.id
        override fun areContentsTheSame(old: Item, new: Item) = old == new
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(getItem(position))
    }

    inner class ViewHolder(private val binding: ItemBinding) :
        RecyclerView.ViewHolder(binding.root) {
        fun bind(item: Item) {
            binding.title.text = item.title
            // ✅ Gunakan placeholder & cache untuk gambar
            Glide.with(binding.root)
                .load(item.imageUrl)
                .placeholder(R.drawable.placeholder)
                .override(200, 200)  // Resize!
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .into(binding.image)
        }
    }
}
Dart — Flutter Rendering Tips
// ❌ Buruk: rebuild semua widget
State build(BuildContext context) {
  return Column(
    children: items.map((item) => ItemWidget(item: item)).toList(),
  );
}

// ✅ Baik: gunakan ListView.builder (lazy build)
ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return ItemWidget(item: items[index]);
  },
)

// ✅ Cache expensive computations
Widget build(BuildContext context) {
  return RepaintBoundary(
    child: CustomPaint(
      painter: ChartPainter(data: data),  // Hanya repaint jika data berubah
    ),
  );
}

// ✅ Gunakan const widgets
const Text('Hello')  // Tidak rebuild
Text('Hello')        // Bisa rebuild

4. Network Optimization

Kotlin — OkHttp Caching
val client = OkHttpClient.Builder()
    .cache(Cache(
        directory = File(context.cacheDir, "http_cache"),
        maxSize = 50L * 1024 * 1024  // 50 MB
    ))
    .addInterceptor { chain ->
        val request = if (isNetworkAvailable()) {
            chain.request().newBuilder()
                .cacheControl(CacheControl.FORCE_NETWORK)
                .build()
        } else {
            chain.request().newBuilder()
                .cacheControl(CacheControl.FORCE_CACHE)
                .build()
        }
        chain.proceed(request)
    }
    .addNetworkInterceptor { chain ->
        val response = chain.proceed(chain.request())
        response.newBuilder()
            .header("Cache-Control", "public, max-age=300")
            .build()
    }
    .connectTimeout(15, TimeUnit.SECONDS)
    .readTimeout(15, TimeUnit.SECONDS)
    .build()

4.1 Network Best Practices

PraktikManfaat
HTTP caching (Cache-Control)Kurangi request ke server
Request batchingSatu request untuk banyak data
Pagination / infinite scrollTidak load semua data sekaligus
Compress response (gzip)Kurangi payload size
Retry with exponential backoffHandle transient failures
Prefetch dataLoad sebelum user butuh

5. Battery Optimization

Kotlin — Battery-Efficient Background Work
// Gunakan WorkManager untuk background task
class SyncWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        return try {
            // Sync data
            val data = api.fetchUpdates()
            database.saveAll(data)
            Result.success()
        } catch (e: Exception) {
            Result.retry()
        }
    }
}

// Schedule dengan constraints
val constraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.UNMETERED)  // WiFi only
    .setRequiresBatteryNotLow(true)
    .build()

val syncRequest = PeriodicWorkRequestBuilder<SyncWorker>(
    repeatInterval = 6, repeatIntervalTimeUnit = TimeUnit.HOURS
)
    .setConstraints(constraints)
    .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 10, TimeUnit.MINUTES)
    .build()

WorkManager.getInstance(context).enqueueUniquePeriodicWork(
    "data_sync", ExistingPeriodicWorkPolicy.KEEP, syncRequest
)
⚠️ Hindari WakeLock

Jangan gunakan WakeLock langsung. Gunakan WorkManager atau AlarmManager untuk scheduled tasks. Android akan menghentikan app yang menyalahgunakan WakeLock.

6. Cold Start Optimization

XML — Android Splash Screen





    
        
        
    

Kotlin — Lazy Initialization
class MyApplication : Application() {
    // ❌ Eager init — lambat di startup
    val heavyService = HeavyService()

    // ✅ Lazy init — init saat pertama kali diakses
    val analytics by lazy { AnalyticsService(this) }
    val database by lazy { Room.databaseBuilder(this, AppDb::class.java, "db").build() }

    override fun onCreate() {
        super.onCreate()
        // ✅ Hanya init yang benar-benar diperlukan
        initCrashReporting()  // Penting: harus duluan

        // ❌ Jangan init semua di sini
        // initAnalytics()
        // initImageLoader()
        // initPushNotification()
    }
}

6.1 Cold Start Timeline

FaseYang TerjadiOptimasi
Process creationOS fork processTidak bisa dioptimasi
Application.onCreateInisialisasi libraryLazy init, defer non-essential
Activity creationLayout inflateViewStub, reduce hierarchy
First frameRender pertamaShimmer/placeholder
Data loadedAPI responseCache, prefetch

Quiz Pemahaman

Pertanyaan 1: Target cold start time yang ideal untuk mobile app?

a) < 10 detik
b) < 5 detik
c) < 2 detik
d) < 1 detik

Pertanyaan 2: Apa penyebab utama memory leak di mobile?

a) Terlalu banyak variabel
b) Retain cycle / circular reference
c) Bitmap besar
d) Cache kebanyakan

Pertanyaan 3: Komponen apa untuk background task yang battery-efficient di Android?

a) AsyncTask
b) IntentService
c) WorkManager
d) Thread

Pertanyaan 4: Pola apa yang menggantikan eager initialization di Application class?

a) Singleton
b) Factory
c) Lazy initialization
d) Builder

Pertanyaan 5: Apa yang dilakukan DiffUtil di RecyclerView?

a) Mengurangi memory
b) Menghitung perbedaan item untuk update efisien
c) Meng-cache gambar
d) Mengompres data
← SebelumnyaKembali ke Beranda Selanjutnya →Lihat Kategori
🔍 Zoom
100%
🎨 Tema