Jetpack Compose 是用于构建原生界面的最新的 Android 工具包,采用声明式 UI 的设计,拥有更简单的自定义和实时的交互预览功能,由 Android 官方团队全新打造的 UI 框架。
官方文档
第三方文档
2、环境配置2.1、新项目可以通过最新的Android studio直接新建Compose项目
2.2、支持Compose项目的具体配置如下
2.2.1、Android studio版本,最好使用最新版本,Android Studio Arctic Fox 或更高版本
2.2.2、Gradlec插件版本7.0 或更高版本
buildscript {
...
dependencies {
classpath
"com.android.tools.build:gradle:7.0.0"
...
}
}
2.2.3、kotlin版本,Kotlin 1.4.32 或更高版本,Compose仅支持kotlin语言
plugins {
id
'org.jetbrains.kotlin:android'
version
'1.5.21'
}
2.2.4、build.gradle配置
build.gradle
android {
compileSdk
31
defaultConfig {
applicationId
"com.gala.composeexample"
minSdk
21
//Compose最低支持api21,即Android5.0,因为Compose的库里面minSdkVersion是21
targetSdk
31
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'
}
}
// Set both the Java and Kotlin compilers to target Java 8.
//本地jdk版本需要11或更高版本
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget =
'1.8'
useIR =
true
}
buildFeatures {
// Enables Jetpack Compose for this module
compose
true
}
composeOptions {
kotlinCompilerExtensionVersion compose_version
kotlinCompilerVersion
'1.5.21'
}
packagingOptions {
resources {
excludes +=
'/META-INF/{AL2.0,LGPL2.1}'
}
}
}
dependencies {
implementation fileTree(include: [
'*.jar'
], dir:
'libs'
)
implementation
'androidx.core:core-ktx:1.6.0'
implementation
'androidx.appcompat:appcompat:1.3.1'
implementation
'com.google.android.material:material:1.4.0'
//Compose 布局、绘制、预览
implementation
"androidx.compose.ui:ui:$compose_version"
implementation
"androidx.compose.ui:ui-tooling-preview:$compose_version"
//Compose 基于 Material Design 的风格化
implementation
"androidx.compose.material:material:$compose_version"
//Compose 状态管理
implementation
"androidx.compose.runtime:runtime-livedata:$compose_version"
implementation
'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
implementation
'androidx.activity:activity-compose:1.3.1'
testImplementation
'junit:junit:4.+'
androidTestImplementation
'androidx.test.ext:junit:1.1.3'
androidTestImplementation
'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation
"androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation
"androidx.compose.ui:ui-tooling:$compose_version"
implementation(
"io.coil-kt:coil-compose:1.4.0"
)
}
相比传统XML的setContentView,Compose使用了ComponentActivity的扩展方法setContent,方法最后还是调用了setContentView
setContent {
ComposeExampleTheme {
//是一个加了注解@Composable的方法
MainCompose(mViewModel)
}
}
//示例显示一个text
@Composable
fun Greeting(name: String) {
Text(text =
"Hello $name!"
)
}
JetPack-Compose 自定义了一个基础容器ComposeView ,以及其他扩展View - AndroidComposeView,并对其进行封装,对外提供了各种我们在上层所使用的各种组件或者容器。
在Compose中setContent后,其初始化了一个ComposeView,并且添加了一个AndroidComposeView,其承载了代码中所写的全部组件,并进行解析,最终绘制在了传统UI中。Compose只允许测量一次,不允许重复测量。Compose会先对整个组件树进行一次Intrinsic测量,然后再对整体进行正式的测量。这样开辟两个平行的测量过程,就可以避免因为层级增加而对同一个子组件反复测量所导致的测量时间的不断加倍了。在Compose里疯狂嵌套地写界面,和把所有组件全都写进同一层里面,性能是一样的!所以Compose没有布局嵌套问题。
3、state状态管理由于 Compose 是声明式工具集,因此更新它的唯一方法是通过新参数调用同一可组合项。这些参数是界面状态的表现形式。每当状态更新时,都会发生重组。可以使用 remember 可组合项记住单个对象。系统会在初始组合期间将由 remember
计算的值存储在组合中,并在重组期间返回存储的值。示例如下,具体看官方文档
val defaultBitmap: Bitmap? =
null
val qrBitmap = remember { mutableStateOf(defaultBitmap) }
...
//代码简略了,具体在demo中,qrBitmap的value值随着协程LaunchedEffect中加载结束会变动
val width = dimensionResource(R.dimen.dimen_300dp).value.toInt()
val height = dimensionResource(R.dimen.dimen_300dp).value.toInt()
val qrUrlStr = qrUrl.value ?:
""
LaunchedEffect(qrUrlStr, width, height) {
QRUtils.createQRImage(qrUrlStr, width, height)
.also { qrBitmap.value = it }
}
qrBitmap.value?.run {
Image(
painter = BitmapPainter(
this
.asImageBitmap()),
contentDescription =
null
,
modifier = Modifier
.padding(top = dimensionResource(R.dimen.dimen_32dp))
.size(
dimensionResource(R.dimen.dimen_300dp),
dimensionResource(R.dimen.dimen_300dp)
),
contentScale = ContentScale.FillBounds
)
} ?: run {
Image(
painter = painterResource(id = R.drawable.a_projection_def_logo),
contentDescription =
null
,
modifier = Modifier
.padding(top = dimensionResource(R.dimen.dimen_32dp))
.size(
dimensionResource(R.dimen.dimen_300dp),
dimensionResource(R.dimen.dimen_300dp)
)
.background(color = colorResource(R.color.color_f0f0f0)),
contentScale = ContentScale.Inside
)
}
4.1、包体大小对比
1、release混淆版本,Compose库大小大概0.5M
2、看一些Compose使用文章,项目完全使用Compose包体大小减少明显,主要在于方法数和layout减少
4.2、耗时分析对比,Compose比XML慢,能肉眼可见会黑一小会
4.2.1 Compose耗时分析
数据是在电视果设备上取的,使用Android studio自带的Profiler分析的,使用Compose的情况下,view显示耗时具体情况如下图,主要在于AndroidComposeView.onAttackedToWindow和onMeasure方法
4.2.2 Compose与XML耗时情况对比
同一个布局样式(项目中的投屏落地页,相对简单,层级不多),release版本,耗时对比统计结果如下(详细结果如图):
如上述表格数据:
- 在电视果5SP(Android7.1)上,Compose比XML慢很多,每次启动清理不清理数据几乎差不多
- 在小米10(Android11)上,每次清理数据的情况,Compose比XML略慢,layout相差50ms左右,draw相差20ms左右;不清理数据的情况,Compose和XML几乎是一样的,相差在10ms以内。不清理数据比清理数据快很多,应该是高Android版本有所缓存
- 经对比,在高性能设备上Compose的view布局、绘制、渲染表现还可以,与XML相差不大,略慢一点
4.3 构建速度,由于demo小比较不明显