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 у предњем плану и има фокус уноса. Разлика се демонстрира на примеру дијалог прозора: када се изнад Activity појави Dialog, Activity губи onResume (позива се onPause), али остаје видљива — onStart/onStop се не позивају.
Табела разлика јасно показује у којим сценаријима се позива свака метода:
| Сценарио | onStart | onResume |
|---|---|---|
| Покретање апликације | Позива се | Позива се |
| Изнад Activity отворен Dialog | Не позива се | 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 са минималним интервалом и дистанцом — на пример, 10 секунди и 10 метара, што даје оптималан баланс између прецизности и потрошње енергије.
Покретање анимација у 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 одмах отвори друга Activity или провидни прозор. На пример, ако се након onCreate покреће екран за аутентификацију (Activity A → Activity B), у Activity A onStart се позива, али onResume не — добија директно onPause → onStop при прекривању екраном B.
onStart може бити позван више пута током живота инстанце Activity. Сваки пут када Activity прелази из скривеног стања (onStop) у видљиво, позива се onStart. У пракси, при активном коришћењу апликације, onStart се може позивати десетине или стотине пута током сесије.
Учитавање података у onStart је оправдано ако подаци треба да се ажурирају сваки пут када се екран појави. На пример, вести или листа обавештења. Али учитавање мора бити асинхроно — преко корутина са lifecycleScope, како не би блокирало UI нит. За податке који се не мењају између појављивања екрана, довољно их је учитати једном у onCreate.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође