Frame Rate — تعداد فریمهایی است که سیستم گرافیکی در یک ثانیه نمایش میدهد. در برنامههای موبایل، نرخ فریم به طور مستقیم نرمی انیمیشنها، اسکرول و انتقال بین صفحهها را تعیین میکند. بر اساس دادههای Android Developers, 2025، Frame Rate هدف برای نمایشگرهای استاندارد 60 fps و برای دستگاههای با نرخ تجدید بالا 120 fps است. انحراف از مقدار هدف منجر به لکنت بصری و کاهش تجربه کاربری میشود.
نکات کلیدی
Frame Rate (نرخ فریم) — معیاری است که بر حسب فریم در ثانیه (fps) اندازهگیری میشود و نشان میدهد که برنامه چند بار در ثانیه تصویر روی صفحه را بهروزرسانی میکند. چشم انسان حرکت را از 24 fps (سینما) به عنوان نرم درک میکند، اما برای UI تعاملی حداقل 60 fps لازم است تا لمسها و انیمیشنها فوری به نظر برسند. هر فریم یک چرخه کامل است: پردازش ورودی کاربر، محاسبه Layout، رندر سلسلهمراتب View و نمایش روی صفحه. اگر هر یک از مراحل از بودجه زمانی تعیینشده (16.6 میلیثانیه در 60 fps) تجاوز کند، فریم از دست میرود و کاربر لکنت میبیند.
تشخیص Frame Rate برنامه از نرخ تجدید نمایشگر (Refresh Rate) مهم است. نرخ تجدید یک ویژگی صفحه است: نمایشگر چند بار در ثانیه تصویر را فیزیکی تجدید میکند (60، 90، 120 یا 144 هرتز). Frame Rate — تعداد فریمهایی است که برنامه در ثانیه رندر میکند. اگر برنامه در نمایشگر 120 هرتز 60 fps تولید کند، هر فریم دوم تکرار میشود — تصویر نرم میماند اما به اندازهای که میتوانست پاسخگو نیست. بر اساس Google I/O 2023، پرچمداران مدرن میتوانند در سناریوهای ساده UI 120 fps را حفظ کنند، اما در بارهای سنگین (بازیها، لیستهای پیچیده) نرخ به 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) همگامسازی میکنند و تضمین میدهند که فریم فقط در لحظه تجدید صفحه نمایش داده شود و از پارگی تصویر (tearing) جلوگیری میکند.
در iOS خط لوله مشابه است: Run Loop رویدادها را پردازش میکند، Core Animation لایهها را محاسبه میکند، Render Server (فرآیند جداگانه) رندر میکند و فریم را به GPU میفرستد. تفاوت iOS — فرآیند جداگانه Render Server که رندر را از برنامه اصلی جدا میکند. اگر برنامه thread اصلی را مسدود کند، Render Server همچنان میتواند آخرین فریم شناختهشده را نمایش دهد اما انیمیشنها متوقف میشوند. اگر خود Render Server نتواند بهموقع کار کند — GPU بیکار میماند و Frame Rate کاهش مییابد. بر اساس Apple WWDC 2022، شایعترین دلایل Frame Rate پایین در iOS — تودرتویی بیش از حد CALayer، shadowPath سنگین و رندر خارج از صفحه (offscreen rendering) است.
کد در 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 هرتز دارند، پرچمداران مدرن — 90، 120 یا 144 هرتز. Frame Rate برنامه میتواند پایینتر، برابر یا بالاتر از نرخ تجدید باشد (در حالت آخر فریمهای اضافی حذف میشوند). سناریوی ایدهآل — Frame Rate با Refresh Rate مطابقت دارد: هر چرخه سختافزاری یک فریم جدید از برنامه دریافت میکند و حرکت حداکثر نرم است. اگر Frame Rate پایینتر باشد، نمایشگر آخرین فریم را تکرار میکند که به عنوان لکنتهای ریز (stutter) درک میشود.
Android و iOS از تغییر پویای نرخ تجدید پشتیبانی میکنند. Android 12+ از Smart Refresh Rate استفاده میکند: هنگام اسکرول سیستم نرخ را به 120 هرتز افزایش میدهد، در محتوای ثابت برای صرفهجویی در باتری به 60 هرتز کاهش میدهد. iOS ProMotion (iPhone 13 Pro و جدیدتر) مشابه کار میکند — نرخ بسته به محتوا از 10 تا 120 هرتز متغیر است. توسعهدهنده باید بررسی کند که آیا دستگاه از نرخ بالا پشتیبانی میکند و بودجه زمانی فریم را تطبیق دهد. اگر برنامه نمیتواند فریم را در 8.3 میلیثانیه (برای 120 هرتز) رندر کند، بهتر است مجبوراً روی 60 هرتز کار کند — این Frame Rate پایدار بدون فریمهای از دست رفته را تضمین میکند.
| نوع نمایشگر | Refresh Rate | بودجه فریم | دستگاهها |
|---|---|---|---|
| استاندارد | 60 هرتز | 16.6 میلیثانیه | بیشتر Android/iOS |
| بالا | 90 هرتز | 11.1 میلیثانیه | OnePlus, Pixel 6+ |
| پرچمدار | 120 هرتز | 8.3 میلیثانیه | iPhone Pro, Galaxy S22+ |
| بازی | 144 هرتز | 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 نشان میدهد که چگونه در Flutter روی FrameTimingCallback مشترک شوید و تعداد فریمهای از دست رفته را ثبت کنید. 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، استفاده از Layoutهای نسبی (RelativeLayout با تعداد زیادی قانون) و فراخوانیهای مکرر requestLayout. راهحل — استفاده از ConstraintLayout یا سلسلهمراتب تخت، اجتناب از تودرتویی بیش از 5–6 سطح. در مرحله Draw — بازترسیم (overdraw): زمانی که یک پیکسل چندین بار در هر فریم کشیده میشود. مثلاً پسزمینه سفید Activity زیر یک fragment نیمهشفاف که زیر آن یک لایه دیگر است — هر پیکسل سه بار کشیده میشود. ابزار Debug GPU Overdraw مناطق مشکل را با نشانگذاری رنگی نشان میدهد. توصیه میشود overdraw در سطح 2x یا پایینتر نگه داشته شود.
در iOS مشکلات اصلی — cornerRadius سنگین و masksToBounds — باعث رندر خارج از صفحه (offscreen rendering) میشوند که در آن Core Animation یک بافر موقت ایجاد میکند، در آن میکشد و سپس نتیجه را به صفحه کپی میکند. Offscreen rendering به راحتی در 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 هرتز در صفحه ثابت تا 30–40٪ در مصرف انرژی GPU صرفهجویی میکند. برای دستیابی به بهترین تعادل بین نرمی و مصرف انرژی توصیه میشود: Frame Rate واقعی را در سناریوهای مختلف اندازهگیری کنید، fps هدف را بسته به صحنه تنظیم کنید (بازی — 60، منو — 30، ویدیو — 24) و حالتها را از طریق کامپوننتهای آگاه از چرخه حیات تغییر دهید تا برنامه هنگام کوچکسازی در پسزمینه منابع را برای رندر 120 fps هدر ندهد.
کد در Swift preferredFramesPerSecond را برای CADisplayLink در iOS تنظیم میکند. هنگام اسکرول نرخ به 120 هرتز افزایش مییابد، هنگام توقف — به 60 هرتز کاهش مییابد.
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 هرتز، 120 fps مطلوب است. مقادیر زیر 30 fps به طور محسوسی تجربه کاربری را کاهش میدهد.
Frame Rate — تعداد فریمهایی که برنامه در ثانیه رندر میکند. Refresh Rate — تعداد دفعاتی که نمایشگر فیزیکی تصویر را در ثانیه تجدید میکند. وقتی Frame Rate کمتر از Refresh Rate است، نمایشگر آخرین فریم را تکرار میکند.
از GPU Profiling در Developer Options، Android Studio Profiler یا Firebase Performance استفاده کنید. برای اندازهگیری برنامهنویسی — Choreographer.FrameCallback با محاسبه فاصله بین فریمها.
Overdraw — کشیدن یک پیکسل چندین بار در هر فریم. هر لایه اضافی زمان فاز Draw را افزایش داده و Frame Rate را کاهش میدهد. Overdraw بهینه 2x، بحرانی — 4x و بالاتر.
در محتوای ثابت Dynamic Frame Rate نرخ را به 30–60 هرتز کاهش میدهد و بار GPU را 30–40٪ کاهش میدهد. هنگام اسکرول نرخ برای نرمی به 90–120 هرتز افزایش مییابد.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید