Frame Rate คือจำนวนเฟรมที่ระบบกราฟิกแสดงผลต่อหนึ่งวินาที ในแอปพลิเคชันมือถือ อัตราเฟรมเป็นตัวกำหนดความลื่นไหลของแอนิเมชัน การเลื่อน และการเปลี่ยนระหว่างหน้าจอโดยตรง ตามข้อมูลจาก Android Developers, 2025 Frame Rate เป้าหมายคือ 60 fps สำหรับจอแสดงผลมาตรฐาน และ 120 fps สำหรับอุปกรณ์ที่มีอัตรารีเฟรชสูง การเบี่ยงเบนจากค่าเป้าหมายทำให้เกิดอาการสะดุดทางภาพและประสบการณ์ผู้ใช้ที่แย่ลง
ประเด็นสำคัญ
Frame Rate (อัตราเฟรม) คือหน่วยวัดที่วัดเป็นเฟรมต่อวินาที (fps) ซึ่งบ่งชี้ว่าแอปพลิเคชันอัปเดตภาพบนหน้าจอกี่ครั้งต่อวินาที ดวงตาของมนุษย์รับรู้การเคลื่อนไหวว่าลื่นไหลตั้งแต่ 24 fps (ภาพยนตร์) แต่ UI แบบโต้ตอบต้องการอย่างน้อย 60 fps เพื่อให้การสัมผัสและแอนิเมชันรู้สึกทันที แต่ละเฟรมเป็นวงจรที่สมบูรณ์: การประมวลผลอินพุตของผู้ใช้ การคำนวณเค้าโครง การเรนเดอร์ลำดับชั้น View และการแสดงผลบนหน้าจอ หากขั้นตอนใดเกินงบประมาณเวลาที่จัดสรร (16.6 มิลลิวินาทีที่ 60 fps) เฟรมนั้นจะถูกข้ามไป และผู้ใช้จะเห็นอาการสะดุด
สิ่งสำคัญคือต้องแยกความแตกต่างระหว่าง Frame Rate ของแอปพลิเคชันกับอัตรารีเฟรชของจอแสดงผล (Refresh Rate) อัตรารีเฟรชเป็นคุณลักษณะของฮาร์ดแวร์หน้าจอ: จอแสดงผลอัปเดตภาพทางกายภาพกี่ครั้งต่อวินาที (60, 90, 120 หรือ 144 Hz) Frame Rate คือจำนวนเฟรมต่อวินาทีที่แอปพลิเคชันสามารถเรนเดอร์ได้ หากแอปพลิเคชันแสดง 60 fps บนจอแสดงผล 120 Hz ทุกเฟรมที่สองจะถูกทำซ้ำ — ภาพจะยังคงลื่นไหลแต่ไม่ตอบสนองเท่าที่ควร ตามข้อมูลจาก Google I/O 2023 เรือธงสมัยใหม่สามารถรักษา 120 fps ในสถานการณ์ UI ที่เรียบง่าย แต่ภายใต้โหลดหนัก (เกม รายการที่ซับซ้อน) อัตราจะลดลงเหลือ 40–60 fps
การเรนเดอร์เฟรมในแอปพลิเคชันมือถือผ่านท่อส่งหลายขั้นตอน ใน Android ท่อส่งประกอบด้วย: การประมวลผลอินพุต (Input), แอนิเมชัน (Animation), การวัดและการจัดวาง (Layout), การวาด (Draw), การซิงโครไนซ์ GPU และการแสดงผลหน้าจอ (Swap) แต่ละขั้นตอนทำงานบน CPU หรือ GPU และเวลารวมของทุกขั้นตอนต้องไม่เกินงบประมาณของเฟรม สำหรับ 60 fps งบประมาณคือ 16.6 มิลลิวินาที สำหรับ 120 fps — 8.3 มิลลิวินาที Choreographer (Android) และ CADisplayLink (iOS) ซิงโครไนซ์การเรนเดอร์กับช่วงเว้นแนวตั้งของจอแสดงผล (VSync) เพื่อให้แน่ใจว่าเฟรมจะแสดงผลเฉพาะในช่วงเวลารีเฟรชหน้าจอเท่านั้น หลีกเลี่ยงการฉีกภาพ
ใน iOS ท่อส่งคล้ายกัน: Run Loop ประมวลผลเหตุการณ์ Core Animation คำนวณเลเยอร์ Render Server (กระบวนการแยกต่างหาก) เรนเดอร์และส่งเฟรมไปยัง GPU ความแตกต่างใน iOS คือกระบวนการ Render Server เฉพาะที่แยกการเรนเดอร์ออกจากแอปพลิเคชันหลัก หากแอปพลิเคชันบล็อกเธรดหลัก Render Server ยังคงสามารถวาดเฟรมสุดท้ายที่รู้จักได้ แต่แอนิเมชันจะหยุดทำงาน หาก Render Server ไม่สามารถตามทัน — GPU จะว่างงานและ Frame Rate จะลดลง ตามข้อมูลจาก Apple WWDC 2022 สาเหตุที่พบบ่อยที่สุดของ Frame Rate ต่ำใน iOS คือการซ้อน CALayer มากเกินไป shadowPath ที่หนัก และการเรนเดอร์นอกหน้าจอ
โค้ด Kotlin สมัครสมาชิก Choreographer.FrameCallback และบันทึกเวลาจริงระหว่างเฟรม หากช่วงเวลาเกิน 16.6 มิลลิวินาที จะบันทึกเฟรมที่พลาด
class FrameRateMonitor {
private var lastFrameTime = 0L
private val frameCallback =
Choreographer.FrameCallback { frameTimeNanos ->
if (lastFrameTime != 0L) {
val deltaMs = (frameTimeNanos - lastFrameTime) / 1_000_000f
if (deltaMs > 16.6f) {
Log.w("FrameRate",
"Skipped frame: $deltaMs ms")
}
}
lastFrameTime = frameTimeNanos
Choreographer.getInstance()
.postFrameCallback(this)
}
fun start() {
Choreographer.getInstance()
.postFrameCallback(frameCallback)
}
}
อัตรารีเฟรช (Refresh Rate) เป็นคุณลักษณะฮาร์ดแวร์ของจอแสดงผลที่กำหนดว่าหน้าจอวาดภาพทางกายภาพกี่ครั้งต่อวินาที จอแสดงผลมาตรฐานมี 60 Hz เรือธงสมัยใหม่มี 90, 120 หรือ 144 Hz Frame Rate ของแอปพลิเคชันอาจต่ำกว่า เท่ากับ หรือสูงกว่าอัตรารีเฟรช (ในกรณีหลัง เฟรมที่เกินจะถูกทิ้ง) สถานการณ์ในอุดมคติคือเมื่อ Frame Rate ตรงกับ Refresh Rate: แต่ละรอบฮาร์ดแวร์ได้รับเฟรมใหม่จากแอปพลิเคชันและการเคลื่อนไหวลื่นไหลสูงสุด หาก Frame Rate ต่ำกว่า จอแสดงผลจะทำซ้ำเฟรมสุดท้าย ซึ่งรับรู้ได้ว่าเป็นการสะดุดระดับจุลภาค
Android และ iOS รองรับการสลับอัตรารีเฟรชแบบไดนามิก Android 12+ ใช้ Smart Refresh Rate: ระหว่างการเลื่อนระบบจะเพิ่มอัตราเป็น 120 Hz บนเนื้อหาคงที่ลดลงเป็น 60 Hz เพื่อประหยัดแบตเตอรี่ iOS ProMotion (iPhone 13 Pro และใหม่กว่า) ทำงานคล้ายกัน — อัตราจะแปรผันจาก 10 ถึง 120 Hz ขึ้นอยู่กับเนื้อหา นักพัฒนาควรตรวจสอบว่าอุปกรณ์รองรับอัตราสูงหรือไม่และปรับงบประมาณเวลาต่อเฟรม หากแอปพลิเคชันไม่สามารถเรนเดอร์เฟรมภายใน 8.3 มิลลิวินาที (สำหรับ 120 Hz) ควรบังคับ 60 Hz — ซึ่งจะรับประกัน Frame Rate ที่เสถียรโดยไม่มีเฟรมพลาด
| ประเภทจอภาพ | อัตรารีเฟรช | งบประมาณต่อเฟรม | อุปกรณ์ |
|---|---|---|---|
| มาตรฐาน | 60 Hz | 16.6 มิลลิวินาที | Android/iOS ส่วนใหญ่ |
| สูง | 90 Hz | 11.1 มิลลิวินาที | OnePlus, Pixel 6+ |
| เรือธง | 120 Hz | 8.3 มิลลิวินาที | iPhone Pro, Galaxy S22+ |
| เกมมิ่ง | 144 Hz | 6.9 มิลลิวินาที | ROG Phone, Nubia RedMagic |
ทั้งเครื่องมือในตัวของแพลตฟอร์มและโปรไฟล์เลอร์ของบุคคลที่สามพร้อมใช้งานสำหรับการวัด Frame Rate ในแอปพลิเคชันมือถือ ใน Android เครื่องมือหลักคือ GPU Profiling (Developer Options → Profile GPU Rendering) ซึ่งแสดงไทม์ไลน์ของแต่ละเฟรมที่แบ่งตามขั้นตอน (Draw, Prepare, Process, Execute) การวิเคราะห์โดยละเอียดยิ่งขึ้นมีให้โดย Android Studio Profiler — บันทึกโปรไฟล์การเรนเดอร์แบบเต็มโดยระบุ View เฉพาะที่ทำให้เกิดการวาดซ้ำ ใน iOS ใช้ Instruments กับเทมเพลต Core Animation — แสดง FPS เวลาเรนเดอร์เลเยอร์ และจำนวนการเรนเดอร์นอกหน้าจอ
สำหรับการตรวจสอบ Frame Rate ในระบบผลิต ใช้ Firebase Performance (Android) — รวบรวม Frame Rate ในพื้นหลังและรวมตามอุปกรณ์ เวอร์ชันระบบปฏิบัติการ และเซสชัน ใน iOS MetricKit ให้ข้อมูลที่คล้ายกันผ่าน MXAnimatoryMetric สำหรับเกมและแอปพลิเคชัน Flutter ใช้ FrameTimingCallback (Flutter) และ Unity Profiler สิ่งสำคัญคือต้องวัดไม่ใช่ค่าเฉลี่ย Frame Rate แต่เป็นเปอร์เซ็นไทล์: P50, P90 และ P99 แอปพลิเคชันอาจแสดงค่าเฉลี่ย 55 fps แต่มี P99 = 30 fps — หมายความว่า 1% ของเวลาผู้ใช้เห็นการสะดุดรุนแรง ซึ่งเพียงพอสำหรับรีวิวเชิงลบ
ตัวอย่าง Dart แสดงวิธีสมัครสมาชิก FrameTimingCallback ใน Flutter และบันทึกจำนวนเฟรมที่พลาด Callback จะทำงานหลังจากแต่ละเฟรมเสร็จสมบูรณ์
import 'package:flutter/scheduler.dart';
class FrameRateLogger {
int totalFrames = 0;
int missedFrames = 0;
void start() {
SchedulerBinding.instance
.addTimingsCallback(_onReportTimings);
}
void _onReportTimings(List<FrameTiming> timings) {
for (final timing in timings) {
totalFrames++;
if (timing.totalSpan()
> Duration(milliseconds: 16)) {
missedFrames++;
}
}
debugPrint("FPS: \${totalFrames - missedFrames}");
}
}
การปรับ Frame Rate ให้เหมาะสมเริ่มต้นด้วยการระบุคอขวดในท่อส่งการเรนเดอร์ ในขั้นตอน Layout ปัญหาหลักคือการซ้อนลำดับชั้น View มากเกินไป การใช้เค้าโครงแบบสัมพัทธ์ (RelativeLayout ที่มีกฎจำนวนมาก) และการเรียก requestLayout บ่อยครั้ง วิธีแก้ไข — ใช้ ConstraintLayout หรือลำดับชั้นแบบเรียบ หลีกเลี่ยงการซ้อนมากกว่า 5–6 ระดับ ในขั้นตอน Draw — overdraw: เมื่อพิกเซลถูกวาดหลายครั้งต่อเฟรม ตัวอย่างเช่น พื้นหลัง Activity สีขาวภายใต้ fragment โปร่งแสงครึ่งหนึ่ง ซึ่งภายใต้มีอีกชั้นหนึ่ง — แต่ละพิกเซลถูกวาดสามครั้ง เครื่องมือ Debug GPU Overdraw แสดงพื้นที่ปัญหาด้วยการระบุสี แนะนำให้รักษา overdraw ไว้ที่ 2x หรือต่ำกว่า
ใน iOS ปัญหาหลักคือ cornerRadius และ masksToBounds ที่หนัก — ทำให้เกิดการเรนเดอร์นอกหน้าจอ ซึ่ง Core Animation สร้างบัฟเฟอร์ชั่วคราว วาดลงไป แล้วคัดลอกผลลัพธ์ไปยังหน้าจอ การเรนเดอร์นอกหน้าจอสามารถสังเกตได้ง่ายใน Instruments Core Animation: หากบรรทัด Renderer เป็นสีแดง — มีปัญหา วิธีแก้ไข — ใช้ UIImageView พร้อมรูปภาพที่ครอบไว้ล่วงหน้าแทน cornerRadius หลีกเลี่ยง groupOpacity และ shouldRasterize เว้นแต่จำเป็นจริงๆ สำหรับทั้งสองแพลตฟอร์ม การลดจำนวนการเรียก invalidate() และ setNeedsDisplay() เป็นสิ่งสำคัญ — การเรียกแต่ละครั้งจะเริ่มวงจรการวาด View ใหม่ทั้งหมด
โค้ดสาธิตการแทนที่การซ้อน RelativeLayout แบบลึกด้วยโครงสร้างแบบเรียบโดยใช้ ConstraintLayout การลดระดับการซ้อนจาก 4 เป็น 1 ช่วยลดเวลา Layout ลง 30–50%
// ตัวอย่าง: โครงสร้างแบบเรียบผ่าน ConstraintLayout
class OptimizedView(context: Context) :
ConstraintLayout(context) {
private val binding =
ItemProfileBinding.inflate(
LayoutInflater.from(context)
)
fun bind(user: User) {
binding.avatar.setImageURI(user.avatarUrl)
binding.nameText.text = user.name
// ผูกข้อมูลโดยไม่ต้องวาดคอนเทนเนอร์ทั้งหมดใหม่
}
}
แอปพลิเคชันมือถือสมัยใหม่ใช้ Frame Rate แบบปรับได้มากขึ้น — ระบบที่ปรับความถี่เป้าหมายแบบไดนามิกตามสถานการณ์ปัจจุบัน การเลื่อนอย่างรวดเร็วต้องการ 120 fps เพื่อความลื่นไหล ในขณะที่หน้าจอคงที่ต้องการเพียง 60 fps หรือแม้แต่ 30 fps สำหรับวิดีโอ ใน Android การปรับใช้ผ่าน Choreographer.setFrameInterval (API 33+) และ Window.setFrameRate นักพัฒนาสามารถระบุความถี่ที่ต้องการ: setPreferredRefreshRate ใน SurfaceView หรือ setFrameRate ใน Window iOS จัดการความถี่โดยอัตโนมัติผ่าน ProMotion แต่นักพัฒนาสามารถตั้งค่า preferredFramesPerSecond สำหรับ CADisplayLink ได้อย่างชัดเจน
Dynamic Frame Rate มีความสำคัญเป็นพิเศษสำหรับเกมและแอปพลิเคชันที่มีแอนิเมชัน ตามข้อมูลของ Google การลด Frame Rate จาก 120 เป็น 60 Hz บนหน้าจอคงที่ประหยัดพลังงาน GPU ได้ถึง 30–40% เพื่อให้ได้สมดุลที่ดีที่สุดระหว่างความลื่นไหลและการใช้พลังงาน ขอแนะนำให้: วัด Frame Rate จริงในสถานการณ์ต่างๆ ตั้งค่า fps เป้าหมายตามฉาก (เกม — 60, เมนู — 30, วิดีโอ — 24) และสลับโหมดผ่านส่วนประกอบ Lifecycle-aware เพื่อให้แอปพลิเคชันไม่สิ้นเปลืองทรัพยากรในการเรนเดอร์ 120 fps ในพื้นหลังเมื่อถูกย่อเล็กสุด
โค้ด Swift ตั้งค่า preferredFramesPerSecond สำหรับ CADisplayLink ใน iOS ระหว่างการเลื่อนอัตราจะเพิ่มเป็น 120 Hz เมื่อหยุดจะลดลงเป็น 60 Hz
class AdaptiveFrameRateManager {
private var displayLink: CADisplayLink?
func startWithHighRate() {
displayLink = CADisplayLink(
target: self,
selector: #selector(step)
)
if #available(iOS 15.0, *) {
displayLink?.preferredFrameRateRange =
CAFrameRateRange(
minimum: 60,
maximum: 120,
preferred: 120
)
}
displayLink?.add(to: .current,
forMode: .common)
}
@objc
private func step() {
// อัปเดตแอนิเมชัน
}
}
คำถามที่พบบ่อย
สำหรับแอปพลิเคชันมือถือ Frame Rate เป้าหมายคือ 60 fps (16.6 มิลลิวินาทีต่อเฟรม) สำหรับอุปกรณ์ที่มีจอแสดงผล 120 Hz ควรได้ 120 fps ค่าที่ต่ำกว่า 30 fps ทำให้ประสบการณ์ผู้ใช้แย่ลงอย่างเห็นได้ชัด
Frame Rate — จำนวนเฟรมต่อวินาทีที่แอปพลิเคชันเรนเดอร์ อัตรารีเฟรช (Refresh Rate) — จำนวนครั้งต่อวินาทีที่จอแสดงผลอัปเดตภาพทางกายภาพ เมื่อ Frame Rate ต่ำกว่า Refresh Rate จอแสดงผลจะทำซ้ำเฟรมสุดท้าย
ใช้ GPU Profiling ในตัวเลือกนักพัฒนา Android Studio Profiler หรือ Firebase Performance สำหรับการวัดเชิงโปรแกรม — Choreographer.FrameCallback พร้อมการคำนวณช่วงระหว่างเฟรม
Overdraw — การวาดพิกเซลเดียวกันหลายครั้งต่อเฟรม แต่ละชั้นที่เพิ่มขึ้นจะเพิ่มเวลาในขั้นตอน Draw และลด Frame Rate Overdraw ที่เหมาะสมคือ 2x ระดับวิกฤตคือ 4x ขึ้นไป
บนเนื้อหาคงที่ Dynamic Frame Rate ลดความถี่ลงเหลือ 30–60 Hz ลดโหลด GPU ลง 30–40% ระหว่างการเลื่อน ความถี่จะเพิ่มเป็น 90–120 Hz เพื่อความลื่นไหล
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม