แอปที่โหลดช้า กระตุก Crash บ่อย หรือกินแบตเตอรี่มาก จะถูกผู้ใช้ลบทิ้งภายใน 24 ชั่วโมง ไม่ว่าฟีเจอร์จะดีแค่ไหนก็ตาม Performance เป็นสิ่งที่ผู้ใช้รับรู้ได้ทันทีและเป็นปัจจัยอันดับหนึ่งที่กำหนดว่าผู้ใช้จะอยู่กับแอปหรือไม่
บทความนี้จะสอนทุกเรื่องเกี่ยวกับ Mobile App Performance Optimization ตั้งแต่การวัดผล เครื่องมือ เทคนิคสำหรับ Android iOS React Native Flutter จนถึง Crash Monitoring และ CI Performance Checks
ทำไม App Performance ถึงสำคัญ?
Performance ไม่ได้แค่เรื่องความเร็ว แต่เกี่ยวข้องกับทุกแง่มุมของธุรกิจแอป:
ผลกระทบต่อ Retention
จากสถิติของ Google แอปที่ใช้เวลาโหลดนานกว่า 5 วินาที จะสูญเสียผู้ใช้ 90% ทันที และผู้ใช้ที่ประสบปัญหา Performance จะมี Day 1 Retention ต่ำกว่าปกติถึง 50% ทุกมิลลิวินาทีที่ลดได้ มีผลต่อการรักษาผู้ใช้โดยตรง
ผลกระทบต่อ Ratings
ผู้ใช้ที่ประสบปัญหา Crash หรือแอปช้ามักจะให้คะแนน 1-2 ดาว และเขียน Review เชิงลบ ซึ่งส่งผลกระทบต่อ ASO และลดโอกาสที่คนใหม่จะดาวน์โหลดแอป
ผลกระทบต่อ Uninstall Rate
แอปที่มีขนาดใหญ่เกินไป กินแบตมาก หรือ Crash บ่อย จะมี Uninstall Rate สูง Android Vitals แสดงว่าแอปที่มี Crash Rate เกิน 1.09% จะถูก Google Play ลด Visibility ในผลค้นหา
| ปัญหา | ผลกระทบ | เกณฑ์ที่ยอมรับได้ |
|---|---|---|
| Startup Time | ผู้ใช้ออกก่อนเข้าแอป | Cold start < 2 วินาที |
| Frame Drop (Jank) | ใช้งานไม่ลื่น รู้สึกช้า | < 1% slow frames |
| Crash | สูญเสียความเชื่อมั่น | Crash-free rate > 99% |
| Battery Drain | ผู้ใช้ลบแอป | < 2% battery/hour (foreground) |
| Memory Leak | แอปช้าลงเรื่อยๆ + OOM crash | Memory stable หลังใช้ 30 นาที |
การวัด Performance
ก่อนจะ Optimize อะไรได้ ต้องวัดให้ได้ก่อน "What you can't measure, you can't improve" Metrics สำคัญที่ต้องวัดมีดังนี้:
Startup Time
เวลาตั้งแต่ผู้ใช้กดเปิดแอป จนกระทั่งหน้าจอแรกแสดงผลครบ แบ่งเป็น Cold Start (เปิดจากศูนย์ไม่มี Process ค้างอยู่) และ Warm Start (Process ยังอยู่ในหน่วยความจำ) Cold Start คือตัวเลขที่สำคัญที่สุดเพราะเป็นประสบการณ์แรกที่ผู้ใช้ได้รับ
Frame Rate
แอปควรแสดงผลที่ 60 FPS (16.67ms ต่อเฟรม) เป็นอย่างน้อย เมื่อ Frame ใช้เวลาเกิน 16ms ผู้ใช้จะเห็นเป็นการกระตุก (Jank) สำหรับจอที่รองรับ 120Hz ต้องลดลงเหลือ 8.33ms ต่อเฟรม
Memory Usage
ปริมาณหน่วยความจำที่แอปใช้ ถ้าใช้เกินกว่าที่ OS อนุญาต แอปจะถูกบังคับปิด (Out of Memory - OOM) Memory ควรคงที่ไม่เพิ่มขึ้นเรื่อยๆ ตามเวลา
Battery Usage
แอปที่ใช้ Battery มากเกินไปจะถูก OS แจ้งเตือนผู้ใช้ และอาจถูก Restrict ไม่ให้ทำงาน Background ผู้ใช้หลายคนตรวจสอบ Battery Usage ใน Settings และลบแอปที่กินแบตมาก
Network Performance
เวลาที่ใช้ในการโหลดข้อมูลจาก API ปริมาณ Data ที่ใช้ และจำนวน Network Requests ต่อหน้าจอ ผู้ใช้ในไทยหลายคนใช้ Data มือถือที่จำกัด แอปที่ใช้ Data มากจะถูกลบ
Android Performance Tools
Android Profiler (Android Studio)
เครื่องมือหลักสำหรับการวิเคราะห์ Performance บน Android มี 4 ส่วนหลัก:
- CPU Profiler: ดู Method trace ว่าฟังก์ชันไหนใช้เวลามากที่สุด จับ Bottleneck ที่ Main Thread
- Memory Profiler: ดู Heap allocation, ตรวจจับ Memory leak, ดู Object retention
- Network Profiler: ดู Request/Response ทั้งหมด ขนาด Payload เวลาที่ใช้
- Energy Profiler: ดูการใช้พลังงาน CPU, Network, GPS, Wake locks
// เปิด Android Profiler:
// Android Studio > View > Tool Windows > Profiler
// เลือก Process ของแอป > เลือก Tab ที่ต้องการ
// ตัวอย่าง: หา Method ที่ช้า
// CPU Profiler > Record > ใช้แอป > Stop
// ดู Flame Chart หรือ Top Down view
// หา Method ที่ใช้เวลานานที่สุด
Systrace / Perfetto
Systrace เป็นเครื่องมือ System-level tracing ที่แสดงว่า CPU แต่ละ Core ทำอะไรอยู่ในแต่ละช่วงเวลา ใช้จับปัญหา Frame drop, Thread scheduling, Lock contention
Perfetto เป็น Next-gen tracing tool ที่มาแทน Systrace รองรับการบันทึกได้นานกว่า มี UI ที่ดีกว่า และวิเคราะห์ได้ละเอียดกว่า ทั้ง Chrome DevTools และ Android Studio ใช้ Perfetto เป็น Backend
# บันทึก Perfetto trace
adb shell perfetto \
-c - --txt \
-o /data/misc/perfetto-traces/trace.perfetto-trace \
<<EOF
buffers: {
size_kb: 63488
fill_policy: RING_BUFFER
}
data_sources: {
config {
name: "linux.ftrace"
ftrace_config {
ftrace_events: "sched/sched_switch"
ftrace_events: "power/suspend_resume"
ftrace_events: "sched/sched_wakeup"
}
}
}
duration_ms: 10000
EOF
# เปิดผลที่ ui.perfetto.dev
iOS Performance Tools
Instruments (Xcode)
Instruments เป็นเครื่องมือ Profiling ที่ทรงพลังที่สุดสำหรับ iOS มี Template มากมาย:
- Time Profiler: วิเคราะห์ว่าโค้ดส่วนไหนใช้ CPU มากที่สุด
- Allocations: ดู Memory allocation ทั้งหมด หา Object ที่สร้างมากเกินไป
- Leaks: ตรวจจับ Memory leak อัตโนมัติ
- Core Animation: วิเคราะห์ Frame rate และหาสาเหตุของ Frame drop
- Network: ดู Network requests ทั้งหมด
- Energy Log: วิเคราะห์การใช้พลังงาน
// เปิด Instruments:
// Xcode > Product > Profile (Cmd+I)
// เลือก Template ที่ต้องการ > Record
// เคล็ดลับ: ทดสอบบน Device จริงเสมอ
// Simulator ไม่สะท้อน Performance จริง
// โดยเฉพาะ GPU rendering และ Memory constraints
MetricKit
MetricKit เป็น Framework ของ Apple ที่เก็บ Performance metrics จากผู้ใช้จริงในสนาม ส่งรายงานมาให้ทุก 24 ชั่วโมง รวมถึง Crash reports, Hang time, Launch time, Memory peaks
// Swift — MetricKit Implementation
import MetricKit
class MetricsManager: NSObject, MXMetricManagerSubscriber {
func didReceive(_ payloads: [MXMetricPayload]) {
for payload in payloads {
// Launch Time
if let launchMetrics = payload.applicationLaunchMetrics {
let histogrammedTime = launchMetrics.histogrammedTimeToFirstDraw
print("Launch time: \(histogrammedTime)")
}
// Hang Rate
if let responsiveness = payload.applicationResponsivenessMetrics {
print("Hang rate: \(responsiveness.applicationHangTime)")
}
}
}
func didReceive(_ payloads: [MXDiagnosticPayload]) {
for payload in payloads {
if let crashDiagnostics = payload.crashDiagnostics {
for crash in crashDiagnostics {
print("Crash: \(crash.callStackTree)")
}
}
}
}
}
React Native Performance
React Native มีปัญหา Performance เฉพาะตัวเพราะต้องสื่อสารระหว่าง JavaScript thread และ Native thread ผ่าน Bridge ทำให้เกิด Bottleneck ได้ง่าย
Hermes Engine
Hermes เป็น JavaScript Engine ที่ Meta สร้างมาเฉพาะสำหรับ React Native ช่วยลด Startup time ได้ 30-50% ลด Memory usage ได้ 20-30% และลดขนาด APK ได้ 10-20% ตั้งแต่ React Native 0.70 ขึ้นไป Hermes เปิดเป็น Default แล้ว
// android/app/build.gradle
project.ext.react = [
enableHermes: true // เปิด Hermes (default ตั้งแต่ RN 0.70+)
]
// ตรวจสอบว่า Hermes ทำงานอยู่:
const isHermes = () => !!global.HermesInternal;
console.log('Hermes enabled:', isHermes());
Bridge Optimization
ลดการสื่อสารข้าม Bridge ให้น้อยที่สุด เพราะทุกครั้งที่ข้าม Bridge ต้อง Serialize/Deserialize ข้อมูล ซึ่งช้า:
- ลด Re-render ด้วย
React.memo,useMemo,useCallback - ใช้
InteractionManager.runAfterInteractionsสำหรับงานหนัก - ย้ายงาน Animation ไปทำ Native side ด้วย
useNativeDriver: true - ใช้ New Architecture (Fabric + TurboModules) เพื่อลด Bridge overhead
FlashList vs FlatList
FlatList เป็น Default list component แต่มีปัญหา Performance เมื่อรายการเยอะ FlashList จาก Shopify เร็วกว่า FlatList 5-10 เท่า เพราะ Recycle cell views แทนการสร้างใหม่
// เปลี่ยนจาก FlatList เป็น FlashList
// npm install @shopify/flash-list
// Before:
import { FlatList } from 'react-native';
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
// After:
import { FlashList } from '@shopify/flash-list';
<FlashList
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
estimatedItemSize={80} // จำเป็นต้องระบุ
/>
Flutter Performance
Flutter มี Performance ดีกว่า React Native ในหลายด้านเพราะ Compile เป็น Native code โดยตรง แต่ก็ยังมีจุดที่ต้องระวัง
Const Widgets
ใช้ const constructor ทุกครั้งที่ Widget ไม่เปลี่ยนแปลง Flutter จะ Cache widget ไว้และไม่สร้างใหม่ตอน Rebuild
// Bad: สร้างใหม่ทุกครั้งที่ Build
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(16),
child: Text('Hello', style: TextStyle(fontSize: 16)),
);
}
// Good: ใช้ const ลดการสร้างใหม่
Widget build(BuildContext context) {
return const Padding(
padding: EdgeInsets.all(16),
child: Text('Hello', style: TextStyle(fontSize: 16)),
);
}
Keys
ใช้ Key อย่างถูกต้องใน List เพื่อให้ Flutter รู้ว่า Widget ไหนเปลี่ยนและไม่ต้อง Rebuild ทั้งหมด:
// ใช้ ValueKey สำหรับ List items
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
key: ValueKey(items[index].id), // ใส่ Key!
title: Text(items[index].name),
);
},
)
RepaintBoundary
ใช้ RepaintBoundary ล้อม Widget ที่ Repaint บ่อยเพื่อไม่ให้กระทบ Widget อื่น ลด GPU workload ได้มาก โดยเฉพาะ Animation และ Scroll
// ล้อม Widget ที่ Animate บ่อยด้วย RepaintBoundary
RepaintBoundary(
child: AnimatedWidget(
// Widget ที่อัปเดตบ่อย
),
)
Flutter DevTools
Flutter DevTools มีเครื่องมือ Performance profiling ครบ:
- Performance Overlay: แสดง Frame rate แบบ Real-time บนหน้าจอ
- Timeline View: ดูว่า Build, Layout, Paint แต่ละ Frame ใช้เวลาเท่าไหร่
- Memory Tab: ดู Memory allocation และหา Leak
- Widget Inspector: ดู Widget tree และหา Unnecessary rebuild
Image Optimization
รูปภาพเป็น Resource ที่ใช้ Memory และ Bandwidth มากที่สุดในแอป การ Optimize รูปภาพมีผลต่อ Performance มหาศาล
WebP Format
ใช้ WebP แทน JPEG/PNG ขนาดไฟล์เล็กกว่า 25-35% โดยคุณภาพเท่ากัน ทั้ง Android และ iOS (14+) รองรับ WebP แล้ว
Image Caching
Cache รูปภาพที่โหลดมาแล้วเพื่อไม่ต้องโหลดซ้ำ:
// Android (Kotlin) — ใช้ Coil (แนะนำ) หรือ Glide
// Coil
implementation("io.coil-kt:coil-compose:2.6.0")
AsyncImage(
model = ImageRequest.Builder(context)
.data("https://example.com/image.webp")
.memoryCachePolicy(CachePolicy.ENABLED)
.diskCachePolicy(CachePolicy.ENABLED)
.build(),
contentDescription = null,
)
// iOS (Swift) — ใช้ Kingfisher หรือ SDWebImage
// Kingfisher
imageView.kf.setImage(
with: URL(string: "https://example.com/image.webp"),
options: [.cacheOriginalImage, .transition(.fade(0.2))]
)
Lazy Loading
โหลดรูปภาพเฉพาะที่อยู่ในหน้าจอเท่านั้น ไม่ต้องโหลดทั้งหมดพร้อมกัน ทุก Framework มี Lazy loading List อยู่แล้ว เช่น RecyclerView (Android), UICollectionView (iOS), FlatList/FlashList (React Native), ListView.builder (Flutter)
Progressive Loading
แสดง Placeholder หรือ Blur preview ขณะที่รูปจริงกำลังโหลด ช่วยให้ผู้ใช้ไม่รู้สึกว่าแอปค้าง เทคนิคที่นิยมคือใช้ BlurHash ที่ Encode รูปเป็นข้อความสั้นๆ แล้วแสดงเป็นภาพ Blur ก่อน
Network Optimization
การ Optimize Network เป็นสิ่งสำคัญมากสำหรับตลาดไทย เพราะผู้ใช้หลายคนใช้ 4G ที่มี Latency สูงกว่า WiFi
Data Compression
เปิด Gzip/Brotli Compression สำหรับ API Response ลดขนาดข้อมูลได้ 60-80% ฝั่ง Server ต้องตั้งค่า และฝั่ง Client ต้องส่ง Accept-Encoding: gzip, br header
HTTP Caching
ใช้ Cache-Control header ให้ Client เก็บ Response ไว้ ไม่ต้อง Request ซ้ำ:
// Server Response Headers:
Cache-Control: max-age=3600 // Cache 1 ชั่วโมง
ETag: "abc123" // สำหรับ Conditional request
// Client จะส่ง:
If-None-Match: "abc123" // ถ้า ETag ตรง Server ตอบ 304 (ไม่ส่ง Body)
Pagination
อย่าโหลดข้อมูลทั้งหมดพร้อมกัน ใช้ Pagination โหลดทีละ 20-50 รายการ รองรับทั้ง Offset-based (?page=2&limit=20) และ Cursor-based (?cursor=abc123&limit=20) โดย Cursor-based เร็วกว่าสำหรับ Dataset ขนาดใหญ่
Offline-first Architecture
เก็บข้อมูลใน Local Database (Room สำหรับ Android, Core Data/SwiftData สำหรับ iOS) แสดงข้อมูล Local ก่อน แล้ว Sync กับ Server ใน Background ผู้ใช้จะรู้สึกว่าแอปเร็วมากเพราะไม่ต้องรอ Network
Memory Management
Memory Leak Detection
Memory Leak เกิดเมื่อ Object ที่ไม่ใช้แล้วไม่ถูก Garbage Collect เพราะยังมี Reference ค้างอยู่ ทำให้ Memory เพิ่มขึ้นเรื่อยๆ จนแอป Crash
// Android — ใช้ LeakCanary (ตรวจจับ Leak อัตโนมัติ)
// build.gradle
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14'
// ไม่ต้องเขียน Code เพิ่ม LeakCanary จะแจ้งเตือนเมื่อพบ Leak
// สาเหตุ Memory Leak ที่พบบ่อย:
// 1. Activity/Fragment reference ใน static variable
// 2. ไม่ Unregister listener/callback
// 3. Inner class ที่ Hold reference ของ Outer class
// 4. Handler ที่ไม่ได้ Remove message
// 5. Bitmap ที่ไม่ได้ Recycle
Cache Eviction Strategy
การจัดการ Cache ต้องมีกลยุทธ์ในการลบข้อมูลเก่า ไม่อย่างนั้น Cache จะโตไม่หยุด:
- LRU (Least Recently Used): ลบข้อมูลที่ไม่ได้ใช้นานที่สุดก่อน เป็นกลยุทธ์ที่นิยมที่สุด
- TTL (Time To Live): ลบข้อมูลที่หมดอายุ เช่น Cache ไว้ 1 ชั่วโมงแล้วลบ
- Size-based: กำหนดขนาด Cache สูงสุด เมื่อเต็มก็ลบอันเก่าออก
Battery Optimization
การใช้ Battery อย่างมีประสิทธิภาพเป็นเรื่องสำคัญ โดยเฉพาะเมื่อ Android และ iOS เข้มงวดกับแอปที่กิน Battery มากขึ้นเรื่อยๆ
Background Tasks
ลดงาน Background ให้เหลือน้อยที่สุด ใช้ API ที่ OS ให้มาสำหรับ Background work:
- Android: ใช้ WorkManager สำหรับงาน Background ที่ต้องทำเสร็จ ห้ามใช้ Service แบบ Long-running ยกเว้นจำเป็นจริงๆ เพราะ Android 14 เข้มงวดมากกับ Foreground Service
- iOS: ใช้ BGTaskScheduler สำหรับ Background App Refresh OS จะจัดเวลาให้เหมาะสมกับสภาพ Battery และ Usage pattern ของผู้ใช้
Location Services
GPS เป็นตัวกิน Battery อันดับหนึ่ง ใช้อย่างประหยัด:
- ใช้
PRIORITY_BALANCED_POWER_ACCURACYแทนPRIORITY_HIGH_ACCURACYถ้าไม่ต้องการความแม่นยำสูง - ลดความถี่ในการ Update location
- ใช้ Geofencing แทนการ Poll location ตลอดเวลา
- หยุด Location updates ทันทีเมื่อไม่ต้องการ
Wake Locks
Wake Lock บังคับให้ CPU/Screen ทำงานอยู่ แม้ผู้ใช้ไม่ได้ใช้แอป กิน Battery มาก ควรหลีกเลี่ยง Wake Lock ถ้าเป็นไปได้ ถ้าจำเป็นต้องใช้ ต้องกำหนด Timeout เสมอและปล่อย Wake Lock ทันทีเมื่อเสร็จ
App Size Reduction
ขนาดแอปมีผลต่อ Conversion Rate โดยตรง จากสถิติของ Google ทุกๆ 6MB ที่เพิ่ม Conversion Rate ลดลง 1%
APK Analyzer (Android)
// Android Studio > Build > Analyze APK
// จะแสดง:
// - DEX files ขนาดเท่าไหร่
// - Resources (รูป, layout, strings) ขนาดเท่าไหร่
// - Native libraries ขนาดเท่าไหร่
// - Assets ขนาดเท่าไหร่
// ใช้ App Bundle แทน APK
// Google Play จะสร้าง APK เฉพาะที่ต้องใช้จริง
// ลดขนาดได้ 20-50%
android {
bundle {
language { enableSplit = true }
density { enableSplit = true }
abi { enableSplit = true }
}
}
Tree Shaking
ลบ Code ที่ไม่ได้ใช้ออกจากแอป ทั้ง Android (R8/ProGuard) และ iOS (Dead Code Stripping) มี Tree shaking ในตัว แต่ต้องตั้งค่าให้ถูกต้อง
ProGuard / R8 (Android)
// build.gradle
android {
buildTypes {
release {
minifyEnabled true // เปิด Code shrinking
shrinkResources true // ลบ Resources ที่ไม่ใช้
proguardFiles getDefaultProguardFile(
'proguard-android-optimize.txt'),
'proguard-rules.pro'
}
}
}
// proguard-rules.pro — ตัวอย่าง Rules ที่จำเป็น
-keep class com.example.model.** { *; } // Keep data classes
-keepclassmembers class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
Crash Monitoring
Firebase Crashlytics
Crashlytics เป็นเครื่องมือ Crash monitoring ฟรีจาก Google ที่นิยมที่สุด จับ Crash ทั้ง Android และ iOS แสดง Stack trace ข้อมูล Device รุ่น OS version และ Breadcrumb ก่อน Crash
// Android — เพิ่ม Crashlytics
// build.gradle (project)
plugins { id 'com.google.firebase.crashlytics' version '3.0.0' }
// build.gradle (app)
implementation platform('com.google.firebase:firebase-bom:33.0.0')
implementation 'com.google.firebase:firebase-crashlytics'
// บันทึก Custom key สำหรับ Debug
FirebaseCrashlytics.getInstance().setCustomKey("user_tier", "premium")
FirebaseCrashlytics.getInstance().log("Loading product list")
Sentry
Sentry เป็นทางเลือกที่รองรับหลายแพลตฟอร์มมากกว่า Crashlytics ใช้ได้ทั้ง Mobile, Web, Backend มี Performance monitoring ในตัว และรองรับ Source maps สำหรับ React Native/Flutter
ANR Prevention (Android Not Responding)
ANR เกิดเมื่อ Main Thread (UI Thread) ค้างนานกว่า 5 วินาที ระบบจะแสดง Dialog "App Not Responding" ให้ผู้ใช้เลือก Force Close ซึ่งเป็นประสบการณ์ที่แย่มาก
สาเหตุ ANR ที่พบบ่อย
- ทำ Network request บน Main Thread
- อ่าน/เขียนไฟล์หรือ Database บน Main Thread
- คำนวณหนักบน Main Thread เช่น Parse JSON ขนาดใหญ่
- Dead lock ระหว่าง Thread
- BroadcastReceiver ทำงานนานเกิน 10 วินาที
วิธีป้องกัน ANR
// ย้ายงานหนักไป Background Thread
// Kotlin Coroutines
viewModelScope.launch {
val result = withContext(Dispatchers.IO) {
// Network request, Database query, File I/O
repository.fetchData()
}
// กลับมาอัปเดต UI บน Main Thread
_uiState.value = result
}
// เปิด StrictMode ใน Debug Build เพื่อจับ ANR ก่อน Release
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.build()
)
}
Testing Performance
Baseline Profiling (Android)
Baseline Profiles ช่วยเร่ง Startup time และ Runtime performance ของ Android app โดย Pre-compile code paths ที่สำคัญ ลด Startup time ได้ 30-40%
// สร้าง Baseline Profile
// 1. เพิ่ม dependency
implementation "androidx.profileinstaller:profileinstaller:1.3.1"
// 2. สร้าง Baseline Profile Generator
@RunWith(AndroidJUnit4::class)
class BaselineProfileGenerator {
@get:Rule
val rule = BaselineProfileRule()
@Test
fun generateProfile() {
rule.collect("com.example.app") {
// Navigate through critical user journeys
pressHome()
startActivityAndWait()
// Scroll, click, navigate...
}
}
}
Regression Testing
ตั้ง Performance budget สำหรับแต่ละ Metric และทดสอบทุกครั้งก่อน Release:
| Metric | Budget | เครื่องมือวัด |
|---|---|---|
| Cold Start Time | < 2 วินาที | Macrobenchmark (Android), XCTest (iOS) |
| Frame Rate | > 58 FPS (97% of frames) | Perfetto, Instruments |
| APK/IPA Size | < 50 MB | APK Analyzer, Xcode Organizer |
| Memory Peak | < 200 MB | Memory Profiler, Instruments |
| Network Payload | < 500 KB/screen | Network Profiler, Charles Proxy |
CI Performance Checks
ใส่ Performance checks ใน CI/CD Pipeline เพื่อจับ Performance regression ก่อนที่จะถึงมือผู้ใช้:
# GitHub Actions — Performance CI
name: Performance Check
on: [pull_request]
jobs:
benchmark:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Setup
uses: actions/setup-java@v4
with:
java-version: '17'
- name: Run Macrobenchmark
run: ./gradlew :benchmark:connectedCheck
- name: Check APK Size
run: |
APK_SIZE=$(stat -f%z app/build/outputs/apk/release/app-release.apk)
MAX_SIZE=52428800 # 50MB
if [ $APK_SIZE -gt $MAX_SIZE ]; then
echo "APK size ($APK_SIZE) exceeds budget ($MAX_SIZE)"
exit 1
fi
- name: Upload Results
uses: actions/upload-artifact@v4
with:
name: benchmark-results
path: benchmark/build/outputs/
นอกจาก CI แล้ว ควรมี Performance Dashboard ที่แสดง Metrics จากผู้ใช้จริง (Production) เช่น Firebase Performance Monitoring หรือ Sentry Performance เพื่อติดตาม Trends ระยะยาว
สรุป
Mobile App Performance Optimization ไม่ใช่สิ่งที่ทำครั้งเดียวแล้วจบ แต่เป็นกระบวนการต่อเนื่องที่ต้องวัดผล ปรับปรุง และติดตามตลอดอายุของแอป เริ่มจากการตั้ง Performance budget กำหนดเกณฑ์ที่ยอมรับได้ จากนั้นใช้เครื่องมือที่เหมาะสมวัด Baseline แล้วค่อยๆ Optimize ทีละจุด
จุดที่ควรเริ่มต้น ให้โฟกัสที่ Startup time เพราะเป็นสิ่งแรกที่ผู้ใช้รู้สึกได้ ตามด้วย Crash rate เพราะทำให้สูญเสียผู้ใช้ทันที แล้วค่อยไล่ไปที่ Memory, Battery, Network ตามลำดับ อ่านบทความอื่นๆ เกี่ยวกับการพัฒนาแอปได้ที่ SiamCafe Blog หรือติดตามเทคนิค Performance เพิ่มเติมที่ iCafe Forex
