☀️Siang
Mobile Development

Mobile App Performance Optimization

TOKEN

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

Artikel: Mobile Performance Artikel: Mobile Performance


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
 ad-slot-wide"> 

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