Android studio
Android Studio Flamingo 版本新建项目时已经没有了Empty Compose Activity 模版
参考: https://developer.android.com/studio/releases?hl=zh-cn#updates-to-npw-nmw
依赖关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +--- androidx.compose.material3:material3 -> 1.0 .0 | +--- androidx.compose.foundation:foundation:1.2 .0 -> 1.3 .0 | | +--- androidx.annotation:annotation:1.1 .0 -> 1.5 .0 (*) | | +--- androidx.compose.animation:animation:1.1 .1 -> 1.3 .0 | | | +--- androidx.annotation:annotation:1.1 .0 -> 1.5 .0 (*) | | | +--- androidx.compose.animation:animation-core:1.3 .0 | | | | +--- androidx.annotation:annotation:1.1 .0 -> 1.5 .0 (*) | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6 .4 (*) | | | +--- androidx.compose.foundation:foundation-layout:1.0 .0 -> 1.3 .0 | | | | +--- androidx.annotation:annotation:1.1 .0 -> 1.5 .0 (*) | | | | +--- androidx.compose.ui:ui:1.2 .0 -> 1.3 .0 (*) | | | | \--- androidx.compose.ui:ui-unit:1.1 .1 -> 1.3 .0 (*) | | | +--- androidx.compose.runtime:runtime:1.1 .1 -> 1.3 .0 (*) | | | +--- androidx.compose.ui:ui:1.0 .0 -> 1.3 .0 (*) | | | \--- androidx.compose.ui:ui-geometry:1.0 .0 -> 1.3 .0 (*) | | +--- androidx.compose.runtime:runtime:1.3 .0 (*) | | \--- androidx.compose.ui:ui:1.3 .0 (*) | +--- androidx.compose.material:material-icons-core:1.0 .2 -> 1.3 .0 | | \--- androidx.compose.ui:ui:1.0 .0 -> 1.3 .0 (*) | +--- androidx.compose.material:material-ripple:1.0 .0 -> 1.3 .0 | | +--- androidx.compose.foundation:foundation:1.1 .1 -> 1.3 .0 (*) | | \--- androidx.compose.runtime:runtime:1.1 .1 -> 1.3 .0 (*) | +--- androidx.compose.runtime:runtime:1.0 .1 -> 1.3 .0 (*) | +--- androidx.compose.ui:ui:1.3 .0 (*) | +--- androidx.compose.ui:ui-graphics:1.0 .1 -> 1.3 .0 (*) | \--- androidx.compose.ui:ui-text:1.3 .0 (*)
libs.versions.toml
https://developer.android.com/build/migrate-to-catalogs
gradle 使用kotlin,2022.3.1的版本开始,默认新建项目使用kotlin gradle
https://developer.android.com/build/migrate-to-kotlin-dsl
side effect LaunchedEffect 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Composable fun LaunchedEffectTest () { val state = remember { mutableStateOf("xiaomi" ) } LaunchedEffect(state) { Log.e("LaunchedEffectTest" , "request" ) delay(3000 ) state.value = "oppo" } Log.e("LaunchedEffectTest" , state.value) Column(modifier = Modifier.padding(10. dp)) { Spacer(modifier = Modifier.padding(top = 50. dp)) Button(onClick = { state.value = "vivo" }) { Text(text = "按钮" ) } Spacer(modifier = Modifier.padding(top = 100. dp)) Text(text = "手机品牌 ${state.value}" ) } }
LaunchedEffect 内部也维护了生命周期,Composable退出时会自动释放。
rememberCoroutineScope 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Composable fun MoviesScreen () { val scope = rememberCoroutineScope() Column { Button( onClick = { scope.launch { Log.d("MoviesScreen" ,"scope.launch" ) } } ) { Text("Press me" ) } } }
rememberCoroutineScope内部会自己维护生命周期,当composable退出时,会自动释放CoroutineScope
rememberUpdatedState 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @Composable fun UpdatedStateTest () { var message = remember { mutableStateOf("start" ) } Column(modifier = Modifier.padding(10. dp)) { Button( onClick = { message.value = "clicked" } ) { Text("描述信息" ) } LoadingScreen(message.value) } } @Composable fun LoadingScreen (text: String, scaffoldState: ScaffoldState = rememberScaffoldState() ) { val messageText by rememberUpdatedState (text) Log.e ("LoadingScreen" , "start" ) LaunchedEffect (true ) { Log.e("LoadingScreen" , "delay origin ${messageText}" ) delay(4000 ) Log.e("LoadingScreen" , "delay remember ${messageText}" ) scaffoldState.snackbarHostState.showSnackbar( message = "切换了方法" , actionLabel = messageText ) } Scaffold(scaffoldState = scaffoldState) { Column(modifier = Modifier.padding(it)) { Text(text = messageText) } } }
LaunchedEffect 中可以感知到messageText的变化
DisposableEffect 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 @Composable fun DisposableEffectTest ( lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current ) { val inputText = remember { mutableStateOf("" ) } Log.e("DisposableEffectTest" , "Composed" ) DisposableEffect(inputText.value) { val observer = LifecycleEventObserver { _, event -> if (event == Lifecycle.Event.ON_START) { Log.e("DisposableEffectTest" , "ON_START" ) } else if (event == Lifecycle.Event.ON_STOP) { Log.e("DisposableEffectTest" , "ON_STOP" ) } } lifecycleOwner.lifecycle.addObserver(observer) onDispose { Log.e("DisposableEffectTest" , "onDispose" ) lifecycleOwner.lifecycle.removeObserver(observer) } } Column(modifier = Modifier.padding(10. dp)) { Button(onClick = { inputText.value = "按了一下" }) { Text(text = "按钮" + inputText.value) } } }
dispose时机:
当value发生变化时触发 onDispose
退出组合SideEffect 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Composable fun RememberAnalytics(){ val name = remember { mutableStateOf("song") } // On every successful composition, update FirebaseAnalytics with // the userType from the current User, ensuring that future analytics // events have this metadata attached SideEffect { Log.d("SideEffect","SideEffect") } Column { Text(name.value) Button(onClick = { name.value= name.value + "a"}) { } } }
将compose转为非compose每次重组都会触发 SideEffect
produceState 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Composable fun loadNetworkImage ( url: String, imageRepository: ImageRepository ) : State<Result<ImageBitmap>> { Log.e("ProduceStateExample" , "loadNetworkImage: invoke" ) return produceState<Result<ImageBitmap>>(initialValue = Result.Loading,url, imageRepository) { val image = imageRepository.loadNetworkImage(url) value = if (image == null ) { Result.Error } else { Result.Success(image) } } } sealed class Result <T >() { object Loading : Result<ImageBitmap>() object Error : Result<ImageBitmap>() data class Success (val image: ImageBitmap) : Result<ImageBitmap>() }
将非compose转为compose
derivedStateOf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 @Composable fun TodoList (highPriorityKeywords: List<String> = listOf("Review" , "Unblock" , "Compose" ) ) { val todoTasks = remember { mutableStateListOf<String>("huawei" , "xiaomi" , "oppo" , "apple" , "Compose" ) } val highPriorityTasks by remember (highPriorityKeywords) { derivedStateOf { todoTasks.filter { highPriorityKeywords.contains(it) } } } Log.e("TodoList" , "todoTasks:${todoTasks.toList().toString()}" ) Log.e("TodoList" , "highPriorityTasks:${highPriorityTasks.toList().toString()}" ) Column(modifier = Modifier.fillMaxWidth()) { LazyColumn { item { Text(text = "add-TodoTasks" , Modifier.clickable { todoTasks.add("Review" ) }) } item { Divider( color = Color.Red, modifier = Modifier .height(2. dp) .fillMaxWidth() ) } items(highPriorityTasks) { Text(text = it) } item { Divider( color = Color.Red, modifier = Modifier .height(2. dp) .fillMaxWidth() ) } items(todoTasks) { Text(text = it) } } } }