One Off the Slack: How Do We Observe Lifecycle Events?

alorma asked:

Is this the best way to get onStart events in compose?

@Composable
 fun MyComposable(
   myViewModel: MyViewModel = getViewModel(),
 ) {
   DisposableEffect("") {
     val observer = LifecycleEventObserver { _, event ->
       alertsViewModel.onLifecycleEvent(event)
     }
     lifecycle.addObserver(observer)
     onDispose { lifecycle.removeObserver(observer) }
   }
   ...
 }
 
 class MyViewModel: ViewModel() {
   fun onLifecycleEvent(event: Lifecycle.Event) {
     when (event) {
       Lifecycle.Event.ON_START -> {
         // track "screen"
       }
     }
   }
 }

(here, lifecycle is coming from the activity somehow… perhaps this is a member function of the activity)

Matthew Inger was not a fan:

To be honest, IMHO, i don’t view a Lifecycle observer as the job of a composition. In my mind, i would pass two lambda functions to to your composable to call.

@Composable
fun MyComposable(
     onStart: () -> Unit,
     onStop: () -> Unit
) {
    DisposableEffect {
       onStart()
       onDispose { onStop() }
    }
}

that said, composables don’t follow the activity or fragment directly. They have their own lifecycle, which may or may not compose and dispose with the container.

alorma then provided the rationale:

the problem is that our data team needs events send at onStart()

Google’s Ian Lake eventually came to the rescue:

If you want onStart and onStop, you must follow the docs and actually observe the Lifecycle - disposal is absolutely not the same thing at all. For example, when you hit the Home button and go back to your launcher, your composables are not disposed at all - the only change is that the Lifecycle is stopped.

I’d probably keep analytics tracking close to the root of your composable hierarchy or the root of your screen (if you’re using Navigation Compose, which provides every screen its own Lifecycle)

Activity-level analytics tracking — the sort of thing that you might need onStart() for — has little to do with composables, or Compose UI, or anything with Jetpack Compose. You would handle that just in your activity.

The problem comes when projects move from activity-centric implementations to composable-centric ones and try to move analytics. If your screens were your activities, you might have analytics events in onStart() of those activities. However, that does not mean that you would continue to use onStart() when you move to composables, as composable screens will come and go without necessarily triggering any lifecycle events. You need to go back to first principles and determine what are the real world events that should trigger recording the analytics values, then decide what is the best mapping to that in the world of Compose UI. The implementation in the world of activities may not closely resemble the implementation in the world of composables.


Read the original thread in the kotlinlang Slack workspace. Not a member? Join that Slack workspace here!