onStart — متد چرخه حیات Android است که وقتی Activity یا Fragment برای کاربر قابل مشاهده میشوند فراخوانی میشود. در این لحظه صفحه روی نمایشگر دستگاه ظاهر میشود، اما هنوز نمیتواند با کاربر تعامل داشته باشد — فوکوس ورودی تا فراخوانی onResume وجود ندارد. متد onStart برای ثبت شنوندگان سیستمی، اتصال به سرویسهای مکانیابی و شروع انیمیشنهایی که باید تا زمانی که کامپوننت روی صفحه قابل مشاهده است کار کنند، ایدهآل است. درباره چرخه حیات کامل Activity در مقاله Activity Lifecycle بیشتر بخوانید.
نکات اصلی
onStart — دومین متد چرخه حیات Activity است که توسط سیستم بعد از onCreate (یا بعد از onRestart هنگام بازگشت از حالت متوقف شده) فراخوانی میشود. در لحظه فراخوانی onStart، Activity یا Fragment روی صفحه قابل مشاهده میشوند. کاربر رابط کاربری را میبیند، اما صفحه هنوز برای تعامل آماده نیست — فوکوس ورودی فقط بعد از onResume ظاهر میشود.
متد onStart بخشی از «عمر قابل مشاهده» (visible lifetime) Activity است — فاصله بین onStart و onStop. در این مدت Activity ممکن است تا حدی توسط پنجرههای دیگر (مثلاً Activity شفاف یا پنجره دیالوگ) پوشانده شود، اما UI آن قابل مشاهده باقی میماند. این تفاوت عمر قابل مشاهده با «عمر در پیشزمینه» (onResume — onPause) است که Activity فوکوس ورودی کامل دارد.
درک این سلسلهمراتب سهسطحی برای توزیع صحیح کد حیاتی است. onCreate — مقداردهی اولیه یکبار مصرف، onStart — اتصال منابع قابل مشاهده، onResume — دسترسی انحصاری به منابع اختصاصی. توسعهدهندهای که این سطوح را اشتباه میگیرد، خطر ایجاد نشت حافظه یا رفتار نادرست برنامه هنگام جابجایی بین صفحات را دارد.
در Activity، متد onStart هر بار که صفحه روی نمایشگر ظاهر میشود فراخوانی میشود — هم در اولین راهاندازی (بعد از onCreate) و هم هنگام بازگشت از حالت پسزمینه (بعد از onRestart). برخلاف onCreate، onStart میتواند چندین بار در طول عمر یک نمونه Activity فراخوانی شود، بنابراین کدی که باید هر بار هنگام ظاهر شدن صفحه اجرا شود در اینجا قرار میگیرد.
class DashboardActivity : AppCompatActivity() {
private val connectivityReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val isConnected = ... // بررسی ConnectivityManager
binding?.statusIndicator?.setColor(
if (isConnected) Color.GREEN else Color.RED
)
}
}
override fun onStart() {
super.onStart()
registerReceiver(
connectivityReceiver,
IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
)
SensorManager.getInstance().registerStepCounter()
}
override fun onStop() {
unregisterReceiver(connectivityReceiver)
SensorManager.getInstance().unregisterStepCounter()
super.onStop()
}
}
قانون کلیدی: همه منابع متصل شده در onStart باید در onStop آزاد شوند. این تضمین میکند که وقتی Activity از صفحه پنهان است، باتری مصرف نمیکند، به رویدادهای سیستمی گوش نمیدهد و حافظه اشغال نمیکند. Android Studio شامل قوانین lint است که درباره ثبت BroadcastReceiver بدون لغو ثبت مربوطه هشدار میدهد.
onStart در Fragment به چرخه حیات Activity-کانتینر وابسته است. Fragment فراخوانی onStart را بعد از اینکه Activity حاوی آن onStart دریافت کرد، دریافت میکند. با این حال، اگر Fragment در حالت تأخیری اضافه شده باشد (FragmentTransaction.commit() بدون addToBackStack)، onStart ممکن است با تأخیر فراخوانی شود.
class MapFragment : Fragment() {
private var mapView: MapView? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
mapView = MapView(requireContext())
return mapView!!
}
override fun onStart() {
super.onStart()
mapView?.onStart()
LocationService.connect(requireContext())
}
override fun onStop() {
mapView?.onStop()
LocationService.disconnect()
super.onStop()
}
}
ویژگی Fragment.onStart: اگر Fragment در ViewPager با offscreenPageLimit = 1 باشد، فرگمنتهای مجاور نیز قبل از اینکه قابل مشاهده شوند onStart دریافت میکنند. این میتواند منجر به ثبت زودهنگام شنوندگان شود. برای چنین مواردی از متد setUserVisibleHint() یا بررسی isVisible در داخل onStart استفاده کنید تا شنوندگان را فقط برای فرگمنتهای واقعاً قابل مشاهده ثبت کنید.
تفاوت اصلی بین onStart و onResume — سطح فعالیت صفحه است. onStart نشان میدهد که Activity روی صفحه قابل مشاهده است، اما لزوماً در پیشزمینه نیست. onResume نشان میدهد که Activity در پیشزمینه است و فوکوس ورودی دارد. تفاوت با مثال پنجره دیالوگ نشان داده میشود: وقتی Dialog روی Activity ظاهر میشود، Activity onResume را از دست میدهد (onPause فراخوانی میشود)، اما قابل مشاهده باقی میماند — onStart/onStop فراخوانی نمیشوند.
جدول تفاوتها به وضوح نشان میدهد که هر متد در چه سناریوهایی فراخوانی میشود:
| سناریو | onStart | onResume |
|---|---|---|
| راهاندازی برنامه | فراخوانی میشود | فراخوانی میشود |
| Dialog روی Activity باز شده | فراخوانی نمیشود | onPause (از دست دادن فوکوس) |
| فشار دکمه «خانه» | onStop (مخفی) | onPause → onStop |
| بازگشت از «اخیراً استفاده شده» | onStart (قابل مشاهده) | onResume (فوکوس) |
| چرخش صفحه | onCreate → onStart | → onResume |
| تماس ورودی | onStop (مخفی) | onPause → onStop |
این جدول به توسعهدهنده کمک میکند تصمیم بگیرد کد خاص را در کدام متد قرار دهد. مثلاً، اگر برنامه باید هنگام هر پوششی (حتی دیالوگ) پخش ویدیو را متوقف کند، کد در onPause قرار میگیرد. اگر ویدیو فقط هنگام پنهان شدن کامل صفحه باید متوقف شود — کد در onStop قرار میگیرد.
onStart — مکان بهینه برای ثبت شنوندگانی است که فقط زمانی که Activity روی صفحه قابل مشاهده است باید کار کنند. این مربوط به سه نوع اصلی از کامپوننتهای سیستمی است: BroadcastReceiver برای رویدادهای سیستمی، LocationListener برای مکانیابی و SensorListener برای سنسورهای دستگاه.
BroadcastReceiver به صورت پویا از طریق Context.registerReceiver() در onStart ثبت میشود و در onStop از طریق unregisterReceiver() لغو ثبت میشود. ثبت پویا بر ثبت ایستا (در مانیفست) ارجحیت دارد، زیرا عمر گیرنده را به دوره مشاهده Activity محدود میکند — برنامه از پیامهای broadcast سیستمی بیدار نمیشود وقتی Activity پنهان است.
private val batteryReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
binding?.batteryText?.text = "$level%"
}
}
override fun onStart() {
super.onStart()
registerReceiver(batteryReceiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
}
override fun onStop() {
unregisterReceiver(batteryReceiver)
super.onStop()
}
مکانیابی و سنسورها — عملیاتهای پرمصرف هستند. درخواست بهروزرسانی GPS در onStart و لغو در onStop تضمین میکند که برنامه وقتی صفحه پنهان است باتری مصرف نمیکند. برای تنظیم دقیق از requestLocationUpdates با حداقل فاصله زمانی و مسافت استفاده میشود — مثلاً ۱۰ ثانیه و ۱۰ متر، که تعادل بهینه بین دقت و مصرف انرژی را فراهم میکند.
شروع انیمیشنها در onStart، نه در onCreate، تضمین میکند که انیمیشن هر بار هنگام ظاهر شدن صفحه شروع میشود. اگر انیمیشن را در onCreate شروع کنید، فقط در اولین ایجاد Activity کار میکند، اما نه هنگام بازگشت از حالت پسزمینه. onStart هر بار که Activity قابل مشاهده میشود فراخوانی میشود، که آن را مکان ایدهآلی برای شروع انیمیشنهای چرخهای و انتقالها میکند.
private lateinit var pulseAnimator: ValueAnimator
override fun onStart() {
super.onStart()
pulseAnimator.start()
binding?.loadingIndicator?.animate()?.alpha(1f)?.start()
}
override fun onStop() {
pulseAnimator.cancel()
binding?.loadingIndicator?.animate()?.cancel()
super.onStop()
}
برای انیمیشنهایی که از ObjectAnimator یا ValueAnimator استفاده میکنند، فراخوانی cancel() در onStop مهم است. اگر انیمیشن بعد از پنهان شدن Activity به کار خود ادامه دهد، منابع GPU و CPU را بیهوده مصرف میکند، عملکرد دستگاه را کاهش میدهد و تخلیه باتری را تسریع میکند. Android Studio Profiler (گراف GPU) به شما امکان میدهد انیمیشنهای فعال را ردیابی و نشتها را شناسایی کنید.
قانون جفت onStart/onStop برای کار با دوربین پیشنمایش (CameraX) نیز کاربرد دارد. باز کردن دوربین در onStart و بستن در onStop تضمین میکند که دوربین برای سایر برنامهها مسدود نشده است وقتی برنامه شما روی صفحه قابل مشاهده نیست. نقض این قانون یکی از دلایل مکرر نظرات منفی در Google Play است.
سؤالات متداول
onStart — برای شنوندگانی که باید تا زمانی که صفحه قابل مشاهده است کار کنند (BroadcastReceiver، LocationListener، SensorListener). onResume — برای منابعی که نیاز به دسترسی انحصاری دارند (دوربین، ضبط ویدیو، تشخیص گفتار). شنوندگان رویدادهای سیستمی نیازی به دسترسی انحصاری ندارند و میتوانند با پوشش جزئی کار کنند — آنها در onStart ثبت میشوند. دوربین باید فقط با فوکوس کامل فعال باشد — در onResume باز میشود.
onStart همیشه فراخوانی میشود اگر Activity به حالت قابل مشاهده برود. تنها سناریوی بدون onStart — Activity ایجاد و بلافاصله پایان مییابد (مثلاً به دلیل خطا در onCreate). در این حالت بعد از onCreate بلافاصله onDestroy فراخوانی میشود. اما این یک سناریوی اضطراری است که نباید در کد درست نوشته شده وجود داشته باشد.
بله، onStart ممکن است onResume را دریافت نکند اگر بلافاصله روی Activity دیگری یا پنجره شفاف باز شود. مثلاً، اگر بعد از onCreate صفحه احراز هویت راهاندازی شود (Activity A → Activity B)، در Activity A onStart فراخوانی میشود، اما onResume نه — بلافاصله هنگام پوشیده شدن با صفحه B onPause → onStop دریافت میکند.
onStart میتواند چندین بار در طول عمر یک نمونه Activity فراخوانی شود. هر بار که Activity از حالت مخفی (onStop) به حالت قابل مشاهده میرود، onStart فراخوانی میشود. در عمل، با استفاده فعال از برنامه، onStart ممکن است دهها یا صدها بار در یک جلسه فراخوانی شود.
بارگذاری دادهها در onStart اگر دادهها باید هر بار هنگام ظاهر شدن صفحه بهروز شوند، توجیهپذیر است. مثلاً، فید خبری یا لیست اعلانها. اما بارگذاری باید ناهمگام باشد — از طریق کوروتینها با lifecycleScope، تا thread UI مسدود نشود. برای دادههایی که بین ظهورهای صفحه تغییر نمیکنند، بارگذاری یکبار در onCreate کافی است.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.