Challenge 2: repeatOnLifecycle in an Activity — Solution class MainActivity : AppCompatActivity() { private val viewModel: TaskViewModel by viewModels() private lateinit var statusText: TextView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) statusText = findViewById(R.id.statusText) lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.uiState.collect { state -> statusText.text = "Loading: ${state.isLoading}" } } } } } // What would happen without repeatOnLifecycle (collecting the Flow // directly instead): // // If the code instead did "lifecycleScope.launch { viewModel.uiState.collect // { ... } }" with no repeatOnLifecycle wrapper, the collection would keep // running continuously for as long as the Activity instance exists — // including while the app is fully backgrounded (past onStop, per // Course 1 Chapter 2). Every emission from uiState would still trigger // the collect block's work (here, a View update) even though the screen // isn't visible to update at all, which is genuinely wasted CPU work, // and in a real app could mean wasted battery or unnecessary continued // processing tied to state the user can't currently see anyway. // repeatOnLifecycle(STARTED) fixes this by cancelling and restarting the // collection automatically as the Activity crosses the STARTED // threshold, so collection only ever runs while genuinely visible. Notes: - lifecycleScope.launch { repeatOnLifecycle(...) { ... } } is the standard nesting — repeatOnLifecycle itself is a suspend function that needs to run inside a coroutine, which is what the outer lifecycleScope.launch provides. - This entire pattern is exactly what collectAsStateWithLifecycle() handles internally in Compose — this challenge is intentionally the "manual" version, for code still using the traditional View system from Course 1.