Mobile Development 6 min read

Implementing Single-Activity Architecture with Jetpack Compose Navigation

The article explains how to adopt a single‑Activity architecture in Jetpack Compose by using the Navigation component’s NavHost and NavController, encapsulating navigation calls in an Action class, and exposing module‑specific NavGraphs, resulting in a clean, scalable routing solution for modern Android apps.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Implementing Single-Activity Architecture with Jetpack Compose Navigation

With the growing adoption of Jetpack Compose, many projects are moving towards a single‑Activity architecture where a single Activity hosts multiple Compose views and navigation is handled by Compose Navigation.

The “single” in single‑Activity is relative; it can refer to a single Activity per business module or per feature. For new modules or features with multiple screens, using a single Activity + multiple ComposeView together with Compose Navigation is recommended.

The core of implementing a single‑Activity architecture in Compose is the Navigation component. Understanding its usage is essential.

Basic Navigation usage

composeView.setContent {
    RainbowTheme() {
        Surface(color = Color.Transparent, modifier = Modifier.fillMaxSize()) {
            A()
        }
    }
}

Example composables A and B:

@Composable
fun A() {
    Button(onClick = {
        // navigate to B
    }) {
        Text("跳转到B")
    }
}

@Composable
fun B() {
    Text("B页面")
}

Define a NavHost:

@Composable
fun NavHostDemo() {
    val navController = rememberNavController()
    NavHost(navController = navController, startDestination = "A_route") {
        composable("A_route") { A(navController) }
        composable("B_route") { B(navController) }
    }
}

NavController provides two core methods used in this context:

navController.navigate("destination_route") – jump to a target page.

navController.popBackStack() – return to the previous page.

To avoid scattering navigation calls across many composables, encapsulate navigation logic in an Action class:

class MessengerAction(private val navController: NavController, activity: Activity) {
    val enterSmsPage: () -> Unit = {
        navController.navigate(MessengerRouteConfig.SEND_SMS_MAIN_PAGE)
    }
    val finishActivity: () -> Unit = {
        activity.finish()
    }
}

Use the Action inside a NavHost:

@Composable
fun MessengerNavHost(startDestination: String, intent: Intent) {
    val navController = rememberNavController()
    val messengerAction = MessengerAction(navController, this)
    NavHost(navController = navController, startDestination = startDestination) {
        composable(MESSENGER_MAIN_PAGE) { MessengerView(messengerAction) }
        composable(SEND_SMS_MAIN_PAGE) { SmsMainPage(messengerAction) }
    }
}

Calling messengerAction.enterSmsPage() from any composable triggers the navigation without directly referencing the NavController.

For larger projects with multiple modules, each module can expose its own NavHost as an extension on NavGraphBuilder , and the app module aggregates them.

In summary, adopting a Compose‑based single‑Activity architecture with Navigation and encapsulated Action objects provides a clean, scalable routing solution for modern Android mobile development.

Mobile DevelopmentandroidJetpack ComposenavigationCompose NavigationSingle Activity
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.