问题
使用Jetpack Compose 写个小项目,一直以为Navigation导航跳转页面的时候,会打开跳转的可组合函数(即页面布局)所在的Activity。
我在启动页加载了logo,发现跳到首页时,logo还在。
/**
*
* author : jake
* e-mail : [email protected]
* time : 2021/8/4 16:32
* description : 页面路由 、 页面导航 、 启动页
*
*/
class LauncherActivity : BaseActivity(){
override fun initialize(savedInstanceState: Bundle?) {
setContent {
Navigator()
}
}
override fun onDestroy() {
super.onDestroy()
logError("onDestroy LauncherActivity")
}
override fun onResume() {
super.onResume()
logError("onResume LauncherActivity")
}
}
/**
* 页面导航
*
* startDestination = "Home"
* startDestination = "Second"
*
* 如果本页只用做路由页面,不写布局,可以跳转到任意指定页面,如上述代码。
*
* 此处只用做导航,默认打开 Home 页面
*/
@Composable
fun Navigator() {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "Home"){
// composable("Launcher"){ LauncherPage(navController) }
composable("Home"){ HomePage(navController) }
composable("Second"){ SecondPage(navController)}
composable("Third"){ ThirdPage(navController)}
}
}
排查
我在Activity中的生命周期方法中加了日志,但是在打开首页时并没有走日志。
PS: 下文中的代码,可用于 ConstraintLayout & Compose 结合使用的示范
/**
*
* author : jake
* e-mail : [email protected]
* time : 2021/8/1 16:28
* description : 首页
*
*/
class MainActivity : BaseActivity() {
override fun initialize(savedInstanceState: Bundle?) {
setContent {
logError("initialize MainActivity")
}
logError("initialize MainActivity")
}
override fun onDestroy() {
super.onDestroy()
logError("onDestroy MainActivity")
}
override fun onResume() {
super.onResume()
logError("onResume MainActivity")
}
}
/**
* ConstraintLayout & Compose
*
* 页面居中
*/
@Composable
fun HomePage(navController: NavController) {
ConstraintLayout(modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()) {
val (button, textTitle , textContent) = createRefs()
Button(onClick = {
navController.navigate("Second")
}, modifier = Modifier.constrainAs(button) {
top.linkTo(parent.top,margin = 16.dp)
bottom.linkTo(parent.bottom,margin = 16.dp)
start.linkTo(parent.start,margin = 16.dp)
end.linkTo(parent.end,margin = 16.dp)
}) {
Text(text = "跳转到第二页")
}
TextButton(onClick = {
navController.navigate("Third")
}, Modifier.constrainAs(textTitle) {
top.linkTo(button.bottom, margin = 16.dp)
end.linkTo(parent.end, margin = 16.dp)
start.linkTo(parent.start, margin = 16.dp)
}){
Text(text = "跳转到第三页")
}
TextButton(onClick = {
toast("~ 跳到你的心里 ~")
}, Modifier.constrainAs(textContent) {
top.linkTo(textTitle.bottom, margin = 16.dp)
end.linkTo(parent.end, margin = 16.dp)
start.linkTo(parent.start, margin = 16.dp)
}){
Text(text = "我该跳哪里呢?")
}
}
}
可以看到上述代码中,我在Activity生命周期中添加了日志,然而控制台并没有输出相应日志。
而且从代码结构中也可以看出,可组合函数(即页面布局)在class的结构体外。
答案
于是,我在首页 MainActivity 的时候,进行了息屏操作,再次回到前台展示,日志如下:
E/^-^app_log: [ (LauncherActivity.kt:44)#onResume ] onResume LauncherActivity
所以,最终结果就是,Jetpack Compose 使用 Navigation 导航到其他Activity的可组合函数(即页面布局)时,并没打开新Activity。
这也就是为什么启动页的logo会在首页出现的原因。
可组合函数(即页面布局)所在的其他Activity更像是容器,并没有实际用途。
更进一步
于是,我尝试着注释掉了 MainActivity 中的 class 结构体,只留下了 可组合函数(即页面布局)
运行项目,令人惊奇的事情发生了:项目可以正常运行!!!
/**
*
* author : jake
* e-mail : [email protected]
* time : 2021/8/1 16:28
* description : 首页
*
*/
//class MainActivity : BaseActivity() {
// override fun initialize(savedInstanceState: Bundle?) {
// setContent {
// logError("initialize MainActivity")
// }
// logError("initialize MainActivity")
// }
//
// override fun onDestroy() {
// super.onDestroy()
// logError("onDestroy MainActivity")
// }
//
// override fun onResume() {
// super.onResume()
// logError("onResume MainActivity")
// }
//}
/**
* ConstraintLayout & Compose
*
* 页面居中
*/
@Composable
fun HomePage(navController: NavController) {
ConstraintLayout(modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()) {
val (button, textTitle , textContent) = createRefs()
Button(onClick = {
navController.navigate("Second")
}, modifier = Modifier.constrainAs(button) {
top.linkTo(parent.top,margin = 16.dp)
bottom.linkTo(parent.bottom,margin = 16.dp)
start.linkTo(parent.start,margin = 16.dp)
end.linkTo(parent.end,margin = 16.dp)
}) {
Text(text = "跳转到第二页")
}
TextButton(onClick = {
navController.navigate("Third")
}, Modifier.constrainAs(textTitle) {
top.linkTo(button.bottom, margin = 16.dp)
end.linkTo(parent.end, margin = 16.dp)
start.linkTo(parent.start, margin = 16.dp)
}){
Text(text = "跳转到第三页")
}
TextButton(onClick = {
toast("~ 跳到你的心里 准备好接受了吗 ~")
}, Modifier.constrainAs(textContent) {
top.linkTo(textTitle.bottom, margin = 16.dp)
end.linkTo(parent.end, margin = 16.dp)
start.linkTo(parent.start, margin = 16.dp)
}){
Text(text = "我该跳哪里呢?")
}
}
}
至此,终于打破了常规的Android开发的认知。
原来 Compose 只需要一个 Activity 即可,可组合函数(即页面布局) 可以按照功能来创建独立的文件。
写在最后
只是,MVVM的搭建,ViewModel 又该如何创建和绑定可组合函数(即页面布局) 的生命周期呢?
class ExampleViewModel : ViewModel() { /*...*/ }
@Composable
fun MyExample(
viewModel: ExampleViewModel = viewModel()
) {
// use viewModel here
}
时至今日,我才明白,为什么看官方文档的绑定ViewModel那么别扭,总算是真相大白了。
ViewModel的生命周期就是与之绑定的可组合函数(即页面布局) 的生命周期。类似于Activity、Fragment。
PS: 可组合函数(即页面布局) 的生命周期
Android Jetpack Compose 用且只用一个 Activity,可组合函数(即页面布局) 按照功能来创建独立的文件。