Jetpack Compose 是用于构建原生 Android 界面的新工具包。它使用更少的代码、强大的工具和直观的 Kotlin API,可以帮助您简化并加快 Android 界面开发,打造生动而精彩的应用。它可让您更快速、更轻松地构建 Android 界面。
Compose的优势:
声明式:直接描述 UI 应该呈现的样子,而不是一步步说明如何实现。
简洁性: 减少模板代码,使得代码更加简洁易读。
可组合性: 通过组合不同的组件来构建复杂的 UI。
工具支持: 完美集成至 Android Studio,提供实时预览和代码完成等功能。
使用
将 Compose 集成到现有项目中,或在新项目中使用它,只需在 Gradle 配置中添加依赖,并确保使用最新版本的 Android Studio,即可开始使用 Compose 构建 UI。相关其资源请参考官方Compose库
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 //gradle配置 plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' } android { namespace 'com.example.mycomposedemo' compileSdk 34 defaultConfig { applicationId "com.example.mycomposedemo" minSdk 21 targetSdk 34 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { useSupportLibrary true } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt' ), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } buildFeatures { compose true } composeOptions { //3 、Compose的版本更改为1.5 .0 kotlinCompilerExtensionVersion '1.5.0' } packagingOptions { resources { excludes += '/META-INF/{AL2.0,LGPL2.1}' } } } dependencies { //compose 核心依赖 implementation "androidx.compose.ui:ui:$compose_ui_version " implementation 'androidx.activity:activity-compose:1.3.1' implementation 'androidx.compose.material:material:1.1.1' implementation "androidx.compose.ui:ui-tooling-preview:$compose_ui_version " }
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 class MainActivity : ComponentActivity () { override fun onCreate (savedInstanceState: Bundle ?) { super .onCreate(savedInstanceState) setContent { FormExampleTheme { Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { ScreenMain() } } } } } @Composable fun ScreenMain () { val navController = rememberNavController() NavHost(navController = navController, startDestination = "main" ) { composable("main" ) { Greeting("Android" ) } } } @Composable fun Greeting (name:String ,modifier:Modifier = Modifier) { Text(text="Hello $name " ,modifier) } @Preview(showBackground = true) @Composable fun GreetingPreview () { FormExampleTheme { ScreenMain() } }
组件
分类 Compose 原生 文本 Text TextView 文本 TextField Edittext 图片 Icon ImageView 图片 Image ImageView Button Button Button Button IconButton Button Button IconToggleButton CheckBox,Switch Button Switch Switch Button RadioButton RadioButton Button Checkbox CheckBox 布局 Box FrameLayout 布局 Column LinearLayout 布局 Row LinearLayout 布局 Scaffold 无 布局 Constraintlayout Constraintlayout 列表 LazyColumn RecyclerView,ListView 列表 LazyRow RecyclerView,ListView 间距类 Spacer Space(估计很多人都没用过)
优化
避免不必要的重绘
在 Compose 中,避免不必要的 UI 重绘是提升性能的关键策略。通过合理使用状态和记忆化技术,如 remember 和 derivedStateOf,它们用于优化状态管理和性能,可以显著减少组件的重组次数。
如果你有一个需要从网络加载的数据列表,可以使用LaunchedEffect
并且只在组件首次加载时触发,避免了因为父组件的重组而导致的不必要的网络请求。。
列表优化
Compose 提供了 LazyColumn 和 LazyRow 等组件,这些组件只渲染可视区域内的元素,从而优化性能和响应速度。
1 2 3 4 5 6 7 8 9 @Composable fun messageList (messages: List <Message >) { LazyColumn { items(messages, key = { message -> message.id }) { message -> Text(text = message.content) } } }
避坑或者面试常问
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 @Composable fun Counter () { var count by remember { mutableStateOf(0 ) } var text by remember { mutableStateOf("" ) } Column { Button( onClick = { count++ } ) { Text("count $count " ) } TextField( value = text, onValueChange = { text = it } ) OtherCounter() } } @Composable fun OtherCounter () { var text by remember { mutableStateOf("Hello world!" ) } Column { Text(text) TextField( value = text, onValueChange = { text = it } ) } }
Compose UI 最核心的一个思想就是:状态向下,事件向上。
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 //正确使用 @Composable fun CounterRoute( viewModel: CounterViewModel = viewModel<CounterViewModel> () ) { val state by viewModel.state .collectAsState() Counter( state = state , on Increment = { viewModel.on Increment() }, on TextChange = { viewModel.on TextChange(it) }, on OtherTextChange = { viewModel.on OtherTextChange(it) }, ) } @Composable fun Counter( state : CounterState, on Increment: () -> Unit, on TextChange: (String) -> Unit, on OtherTextChange: (String) -> Unit, ) { Column { Button( on Click = { on Increment.invoke() } ) { Text("count ${state.count}" ) } TextField( value = state .text, on ValueChange = { on TextChange.invoke(it) } ) OtherCounter( text = state .otherText, on TextChange = on OtherTextChange, ) } } @Composable fun OtherCounter( text: String, on TextChange: (String) -> Unit, ) { Column { Text(text) TextField( value = text, on ValueChange = { on TextChange.invoke(it) } ) } }
DisposableEffect、SideEffect、LaunchedEffect之间的区别?
DisposableEffect:用于在Composable function的生命周期内执行副作用,并在其离开组合时清理这些副作用。适用于需要清理的副作用,例如注册和注销广播接收器。
SideEffect:用于在组合完成后执行副作用,且这些副作用不会影响UI的重组。适用于不需要清理的副作用,例如记录日志。
LaunchedEffect:用于在组合完成后启动协程,以执行异步操作。适用于需要异步执行的副作用,例如网络请求。
pointer事件在各个Composable function之间是如何处理的?
在Jetpack Compose中,pointer事件由Modifier.pointerInput处理。每个Composable function都可以使用这个修饰符来拦截和处理pointer事件。事件处理可以通过awaitPointerEventScope和其他相关函数来实现,允许开发者自定义事件的处理逻辑和传播方式。
CompositionLocal起什么作用?staticCompositionLocalOf和compositionLocalOf有什么区别?
CompositionLocal用于在Composable tree中共享数据,而无需显式地将数据作为参数传递。staticCompositionLocalOf和compositionLocalOf的区别在于:
staticCompositionLocalOf:用于定义静态的CompositionLocal,生命周期与整个应用程序的生命周期一致。
compositionLocalOf:用于定义动态的CompositionLocal,生命周期与其所在的Composable tree一致。
Composable function的状态是如何持久化的?
Composable function的状态通过remember和rememberSaveable来持久化。remember用于在Composable function重新组合时保持状态,而rememberSaveable
在配置更改(如屏幕旋转)时也能保持状态。
如何解决LazyColumn和其他Composable function的滑动冲突?
可以使用Modifier.nestedScroll来解决LazyColumn和其他Composable function的滑动冲突。这个修饰符允许多个滑动容器协同工作,处理滑动事件的嵌套。
Jetpack Compose多线程执行是如何实现的?
Jetpack Compose通过Kotlin协程来实现多线程执行。LaunchedEffect和rememberCoroutineScope等工具允许在Composable function中启动和管理协程,以执行异步任务。
当一个 Flow 被 collectAsState,应用转入后台时,如果这个 Flow 再进行更新,对应的 State 会不会更新?对应的 Composable 函数会不会更新?
当应用转入后台时,如果Flow继续更新,collectAsState将继续接收这些更新并更新对应的State。由于Composable函数依赖于这个State,因此它们也会相应地更新。
建议开启R8
R8 对于 Compose 的提升是非常巨大的,如果是简单 UI 的话没有 R8 可能还可以用,复杂 UI 下非常推荐开启 R8,代码优化之后的性能的 Debug 的性能差距极大。
及时关闭资源流
对于资源管理,例如打开和关闭连接或订阅,及时使用 DisposableEffect 监听onDispose事件,及时关闭资源。
总结
总之,Jetpack Compose 提供了一种现代化、高效且直观的方式来构建 Android 应用的用户界面。但在跨平台上Compose版本仅支持5.0以上,与fultter相比,fultter最低版本支持4.1,可以根据业务选择使用。