Jetpack Compose Fragment Lifecycle — Building a Tabbed App
--
We’ll create a simple app with three screens and manage their lifecycles using Jetpack Compose and the Lifecycle
library.
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 —
Screen1 -
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.