Compose 使用介绍


本站文档最后更新于:2026-01-13

本文不介绍引入框架依赖部分,如不了解如何引入依赖,请查看文档【从零接入 TheRouter】:https://therouter.cn/docs/2022/11/23/01

本文介绍的完整使用 demo 可以参考:https://github.com/kymjs/TheRouterComposeDemo

从 1.3.1-rc1 版本开始,TheRouter 也支持 Jetpack Compose 了。
需要引入 compose 依赖:

implementation "cn.therouter:compose:1.3.1-rc5"

如果是使用的 libs.versions.toml 建议如下方式引入

[versions]
therouter="1.3.1-rc5"

[libraries]
therouter-router = { module = "cn.therouter:router", version.ref = "therouter" }
therouter-compose = { module = "cn.therouter:compose", version.ref = "therouter" }
therouter-apt = { module = "cn.therouter:apt", version.ref = "therouter" }

[plugins]
therouter-classpath = { id = "cn.therouter", version.ref = "therouter" }
therouter-plugin = { id = "therouter"}


1.0 初始化

框架内部包含自动初始化功能,详见单模块自动初始化能力 无需任何初始化代码。但推荐你根据业务设置否为Debug环境,用以查看日志信息。
Application.attachBaseContext() 方法中尽可能早设置当前是否为Debug环境。

override fun attachBaseContext(base: Context?) {
    TheRouter.isDebug = false // or true
    super.attachBaseContext(base)
}


1.1 声明 @Composable 页面(Screen)

关于注解@Route的参数含义,请查看文档:页面导航跳转能力

⚠️@Composable页面必须是 top-level 级别函数

@Route(path = PathIndex.EMPTY_PAGE, description = "空白页面")
@Composable
fun EmptyComingSoon(modifier: Modifier = Modifier) {
 // xxxxx
}


@Composable 页面的函数定义允许有参数声明。
也允许自定义函数参数的接收key(对应跳转页面时的传参)


@Route(path = PathIndex.MAIN_PAGE, description = "主页")
@Composable
fun ReplyInboxScreen(
    // 普通对象或基本数据类型不需要做任何处理,默认接收key就是变量名
    contentType: ReplyContentType,
    
    // 可以通过注解修改参数的接收 key
    @Autowired(name = "hello_key")
    hello: String,
    
    displayFeatures: List<DisplayFeature>,
    
    toggleSelectedEmail: (Long) -> Unit,
    
    // 有默认值的普通对象,或基本数据类型参数也不需要特殊处理
    modifier: Modifier = Modifier,
) {
//xxxxxxx
}


1.2 打开一个 @Composable 页面(Screen)

与原多 Activity 模式的跳转没有任何区别,只是结尾跳转的方法名变成了compose()

compose() 函数本身也添加了 @Composable 注解,也就是说你可以将TheRouter与传统的 NavHost 混用(虽然不推荐),而没有任何问题。

TheRouter.build(PathIndex.MAIN_PAGE)
    .withObject("contentType", contentType)
    .withString("hello_key",hello_key)
    .withObject("displayFeatures", list)
    .withObject("toggleSelectedEmail", {arg-> println(arg)})
    .compose()


传递一个 @Composable 参数


TheRouter.build(PathIndex.SCREEN)
	// 入参已经声明过 @Composable ,可以直接使用
    .withComposableObject("content"){
        // xxxxxx
    }.compose()

@Composable
@Route(path = PathIndex.SCREEN)
fun ContrastAwareReplyTheme(dynamicColor: Boolean = false,
    content: @Composable () -> Unit,
) {
	// xxxxx
}


1.3 动态 UI 应用

利用 TheRouter 的远端路由下发和路由表的动态性,可以做到线上环境千人千面,以及做到类似低代码UI的效果。


由于 Compose 支持嵌套,也就是一个 Compose Screen 作为另一个 Screen 的参数。用 TheRouter 来实现以后,也就是一个 path 允许关联多个子 path。 而这些 path 的关系靠后端维护,前端只负责渲染。 后端只需要对不同的人,返回不同的预定义 UI 模板的 json 即可。

这样做了以后,相当于把所有的页面 UI 也模块化了,每个 UI 模块只需要提前定义好 UI 样式,让后端返回不同的 path,客户端只负责渲染。看下面一个例子:

// 定义一个 UI,此处简单写一个 Text
@Route(path = "text1")
@Composable
fun ui(str: String) {
    Text(
        modifier = Modifier.padding(start = 10.dp, end = 10.dp),
        text = str,
        style = MaterialTheme.typography.titleMedium,
    )
}

// 定义另一个 UI,此处简单写一个 Text
@Route(path = "text2")
@Composable
fun ui(str: String) {
    Text(
        modifier = Modifier.padding(start = 5.dp, top = 5.dp, end = 5.dp),
        text = str,
        style = MaterialTheme.typography.titleMedium,
    )
}

此时根据后端返回不同的 json,客户端可以展示不同的 Text 样式

val path = "来自服务端返回的 json 中解析到要展示的 path"

TheRouter.build(path).withObject("str", text).compose()

1.4 动态 UI 定义数据源

在上面的例子中,每个 Text 要展示的文案是需要在路由构建时就传入的,不同的 UI 有可能会有不同的数据类型,如果全部要在跳转时写好,明显不利于动态性。我们可以对不同的 UI 模块定义不同的数据来源。甚至你可以对同一个 UI 模块定义多个动态来源,比如从网络/本地缓存/内存缓存 中获取,TheRouter 会根据你定义的优先级,依次获取,如果高优先级没有数据,就从低一级再次获取,直到获取到数据为止。


还是接 1.3 的例子,比如我们现在想让 Text1 和 Text2 的数据来源不同。需要给每一个需要定义数据源的 UI 写一个数据提供者方法,方法名可以随意。

⚠️ 注:

注解参数解释:

// 定义一个 UI,此处简单写一个 Text
@Route(path = "text3")
@Composable
fun ui(hello: String,  user: User) {
    Text(
        modifier = Modifier.padding(start = 5.dp, end = 5.dp),
        text = hello + user.name,
        style = MaterialTheme.typography.titleMedium,
    )
}

// 这里给 text3 定义数据源,因为 text3 有多个参数,且 hello 参数不是类型的小
// 写,所以必须显式声明 fieldName,声明的 fieldName 必须和形参一致
@DataProvider(path = "text3", fieldName = "hello")
fun make1(navigator: Navigator): String {
    return navigator.getUrlWithParams()
}

// 这里给 text3 定义另一个数据源,因为user参数名是类型的小写,所以即便 text3 有多个参数,也不必显式声明 fieldName
@DataProvider(path = "text3")
fun make2(navigator: Navigator): User {
    return "自己创建 User 对象,示例就不写了"
}

定义好数据源以后,在路由跳转的时候,不需要再传入数据了,框架会自动注入数据源

TheRouter.build("text3").compose()

相关推荐:

鸿蒙路由源码调试步骤鸿蒙路由源码调试步骤

本文已迁移至:https://kymjs.com/code/2025/03/23/01/

1 mins
从零接入鸿蒙路由 TheRouter从零接入鸿蒙路由 TheRouter

TheRouter 是货拉拉基于HMRouter深度定制的开源路由框架,提供了 Android、iOS、Harmony 三端高一致性使用,在支持平台化应用...

10 mins
为 TheRouter 的 AGP8 编译加个速为 TheRouter 的 AGP8 编译加个速

内容请见: 《为 TheRouter 的 AGP8 编译加个速》 https://kymjs.com/code/2024/10/31/01/

1 mins