0%

Android-Jetpack组件之Compose

概述

Jetpack Compose 是一个用于构建原生 Android UI 的工具包,它基于声明式的编程模型,因此可以简单地描述 UI 的外观,而 Compose 则负责其余的工作。当状态发生改变时,UI 将自动更新。由于 Compose 基于 Kotlin 构建,因此可以与 Java 互操作,并且可以直接访问所有 Android 和 Jetpack API。它与现有的 UI 工具包也是完全兼容的,因此可以混合原来的 View 和现在新的 View,并且从一开始就使用 Material 和动画进行设计。

基础使用

可以直接创建一个支持 Compose 的工程,也可以在现有工程上添加依赖和配置使其支持 Compose 功能。使用正式版的 AS 时会提示: Jetpack Compose is a preview feature, and support for Compose is included only in Canary(金丝雀) versions of Android Studio. 该功能只是一个预览功能,需要在灰度版本里才能支持。

根项目构建脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
buildscript {
repositories {
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

allprojects {
repositories {
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
}
}

app模块构建脚本:

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
plugins {
id 'com.android.application'
id 'kotlin-android'
}

android {
defaultConfig {
minSdkVersion 21
}

buildFeatures {
compose true // Enables Jetpack Compose for this module
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

kotlinOptions {
jvmTarget = '1.8'
}
}

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.ui:ui-tooling:0.1.0-dev02'
implementation 'androidx.ui:ui-layout:0.1.0-dev02'
implementation 'androidx.ui:ui-material:0.1.0-dev02'
}

HelloWorld

1
2
3
4
5
6
7
8
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Text("Hello World!")
}
}
}

Composable函数

Jetpack Compose 是围绕 composable 函数来构建的,这些函数使你可以通过描述应用程序的形状和数据依赖,以编程方式定义应用程序的UI,而不是着眼于 UI 的构建过程。要创建 composable 函数,只需要在函数名前面加上一个 @composable 注解即可,上面的 Text 就是一个 composable 函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Greeting("World")
}
}
}

@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}

在编译过程中,Compose 会对于加了 @Composable 注解的函数做出不一样的编译逻辑,让这些函数可以在 App 运行时变成我们的界面,正确地显示。这与注解处理器不同,注解处理器会修改 Kotlin 代码,而编译器插件是直接修改字节码的输出逻辑。

@Composable 之所以要用注解而不是跟协程一样增加 suspend 关键字,是因为它是 Android 平台的特性而不是 Kotlin 语言层面的功能。

命令式和声明式UI

所谓声明式 UI,指的就是你只需要把界面给「声明」出来,而不需要手动更新。当我们将界面状态通过变量传递给 Compose 组件时,Compose 里的界面元素会对依赖的数据自动进行订阅,这样数据改变了,界面马上就跟着变。

DataBinding 并不能做到声明式 UI,它是一种数据绑定。

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Activity 的扩展函数
fun Activity.setContent(content: @Composable() () -> Unit): CompositionContext? {
val composeView = window.decorView.findViewById<ViewGroup>(android.R.id.content)
.getChildAt(0) as? AndroidComposeView ?: AndroidComposeView(this).also {
// 给 Activity 设置布局
setContentView(it)
}

val coroutineContext = Dispatchers.Main
return Compose.composeInto(composeView.root, this) {
WrapWithAmbients(composeView, this, coroutineContext) {
content()
}
}
}