Jetpack Compose Fragment Lifecycle — Building a Tabbed App

Dheeraj Singh Bhadoria
4 min readMay 25

--

We’ll create a simple app with three screens and manage their lifecycles using Jetpack Compose and the Lifecycle library.

Jetpack Compose Fragment Lifecycle Article

Introduction:
In this article, we will delve into the process of handling fragment lifecycles in a Jetpack Compose app that incorporates a tabbed interface. We will construct a simple application featuring three screens — “Profile,” “Feed,” and “Settings.” Through the utilization of Jetpack Compose and the Lifecycle library, we will meticulously manage the lifecycles of these screens, ensuring smooth transitions and efficient resource management. By following along, you will gain insights into effectively organizing and maintaining the lifecycle events of fragments within a tabbed app, enabling you to create robust and responsive user interfaces. So let’s dive in and explore the intricacies of Jetpack Compose fragment lifecycles in a tabbed app context.

Our app will consist of a tab bar at the top and three screens: “Profile,” “Feed,” and “Settings.” We’ll use the Scaffold composable from Jetpack Compose to set up the layout and navigation. Each screen will have its own lifecycle, which we'll manage using the Lifecycle library.

Getting Started

Let’s start by creating a new Android project in Android Studio and setting up the necessary dependencies. Open the build.gradle file for your app module and add the following dependencies:

dependencies {
// Jetpack Compose
implementation "androidx.activity:activity-compose:1.4.0"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha07"
}

Sync the project to fetch the dependencies.

Building the Tabbed App

Step 1: Create the Screens

We’ll start by creating the three screens: Screen1, Screen2, and Screen3. These screens will be composed of simple @Composable functions that display some text. Additionally, we'll pass the Lifecycle instance to each screen to handle the lifecycle events.

@Composable
fun Screen1(lifecycle: Lifecycle) {
// Screen1 content
}

@Composable
fun Screen2(lifecycle: Lifecycle) {
// Screen2 content
}

@Composable
fun Screen3(lifecycle: Lifecycle) {
// Screen3 content
}

Step 2: Setup the Navigation

Next, let’s set up the navigation using the NavHost composable from the Navigation Compose library. We'll create a NavController and define the routes for each screen.

In the App composable, we create a NavController using rememberNavController(). We also define a list of screen routes (screens) and a currentScreen variable to keep track of the currently selected screen. Inside the NavHost, we associate each route with its respective screen composable.

Step 3: Manage Lifecycle

To handle the lifecycle events for each screen, we’ll pass the Lifecycle instance to the respective screens and observe the ON_RESUME event. We'll use the DisposableEffect composable to add and remove the lifecycle event observer.

    val onResumeEventObserver = remember(lifecycle) {
object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (event == Lifecycle.Event.ON_RESUME) {
// Handle onResume event
// This code will be executed when the associated Android component resumes
// You can perform any necessary actions here
println("onResume Screen1")
}else if(event== Lifecycle.Event.ON_PAUSE){
println("onPause Screen1")
}else if(event== Lifecycle.Event.ON_CREATE){
println("onCreate Screen1")
}else if(event== Lifecycle.Event.ON_START){
println("onStart Screen1")
}else if(event== Lifecycle.Event.ON_STOP){
println("onStop Screen1")
}else if(event== Lifecycle.Event.ON_DESTROY){
println("onDistory Screen1")
}
}
}
}

DisposableEffect(lifecycle) {
lifecycle.addObserver(onResumeEventObserver)
onDispose {
lifecycle.removeObserver(onResumeEventObserver)
}
}

In each screen composable, we define an onResumeEventObserver that implements the LifecycleEventObserver interface. Inside the observer's onStateChanged function, we check for the ON_RESUME event and perform the necessary actions. In this example, we simply print a log statement.

Next, we use the DisposableEffect composable to add and remove the observer based on the lifecycle. When the composable is initially created, we add the observer using lifecycle.addObserver(onResumeEventObserver). And when the composable is disposed, we remove the observer using lifecycle.removeObserver(onResumeEventObserver).

By implementing this pattern for each screen, we can handle the ON_RESUME event independently for each screen.

Step 4: Complete the App Composition

Finally, we need to complete the App composable by adding the Scaffold and TabRow components to create the tabbed layout.

In the Scaffold composable, we provide the topBar parameter where we build the TabRow component. We use the selectedTabIndex parameter to indicate the currently selected tab based on the currentScreen variable. Inside the TabRow, we iterate over the screens list and create a Tab for each screen. When a tab is clicked, we update the currentScreen variable and navigate to the corresponding route using the navController.

Finally, we wrap the NavHost with the Scaffold and apply innerPadding to ensure proper spacing within the layout

Complete Code —

App.kt

Screen1 -

Screen1.kt

Screen2 -

Screen3 —

Conclusion

In this article, we explored how to handle the fragment lifecycle in a Jetpack Compose app using the Lifecycle library. We created a tabbed app with three screens and managed their lifecycles independently. By observing the ON_RESUME event for each screen, we were able to perform specific actions when a screen is resumed. This approach provides a clean and efficient way to manage lifecycles in a Jetpack Compose app with a tabbed interface.

Github Repository —

--

--