稀有猿诉

十年磨一剑,历炼出锋芒,说话千百句,不如码二行。

降Compose十八掌之『亢龙有悔』

Jetpack Compose是新一代的声明式的UI开发框架,由Google在2019年推出,最初是作为Android的新式UI开发框架,但它本质是一个声明式UI开发框架,并不受制于底层的平台,现在的Compose已有跨平台开发能力,但Android上的UI开发仍是最主要的使用领域,深受Android开发者喜爱。计划将用一系列文章,并开辟专栏来学习Compose,此为开篇。

注意:最初是叫做Jetpack Compose,作为Jetpack套件中的一个,后来与Jetpack独立开来了,现在Compose发展成为一个独立的声明式的UI开发框架,与Jetpack中其他组件并不是同一个概念,也并不在Jetpack套件里面。所以现在更多的称为Compose,为了方便后续统一称为Compose。

Hello, Compose!

老规矩,先来个简单的『Hello, world!』,以快速上手体验:

首先,用Android Studio创建一个新的项目,选择『Phone and Tablet』,选择『Empty Activity』,然后Next。

create project

在项目配置页面填入项目名字和包名等信息,其余的用默认就好。

config project

等一会儿后,项目就创建好了,与常规的Android项目一样的,也有AndroidManifest,是项目运行时的主要配置,以及一个系统组件MainActivity作为入口。打开MainActivity.kt,可以发现里面已经默认用了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
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            HelloComposeTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    Greeting("Android with Compose!")
                }
            }
        }
    }
}

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

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    HelloComposeTheme {
        Greeting("Android")
    }
}

然后构建并运行项目,就能得到一个『Hello, Android with Compose!』:

HelloCompose

样子略丑,我们来优化一下,修改Greeting函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Box(modifier = Modifier.fillMaxSize()) {
        Text(
            text = "Hello, $name",
            modifier = modifier
                .padding(16.dp)
                .align(Alignment.Center),
            style = MaterialTheme.typography.headlineLarge,
            color = MaterialTheme.colorScheme.inverseSurface
        )
    }
}

这下好了一丢丢!

HelloCompose v2

除了在手机或者模拟器运行应用以外,还可以直接用Android Studio进行预览(用@Preview标记的函数才会被预览),不过这不算新功能,因为很久以前打开一个XML文件(如布局),也可以直接在AS里预览的:

preview

好了,现在我们已经成功学会用Compose来撸安卓UI了。如果有时间还可以试试官方的入门Demo

注意:不同版本的Android Studio可能会略不一样。详见下节『开发环境配置』。

配置开发环境

新一点的Android Studio如Giraffe,如果是新建的项目,默认就是用Compose了,不用再怎么搞(如果是上古时代的AS估计还是View的,建议直接升级AS吧都4202年了)。

如果是现有的项目,想要添加Compose支持,可以这样做,先给android的buildFeatures中添加compose为true,并指定kotlin compiler extension的版本,注意这个并不是kotlin的版本,跟它没关系:

1
2
3
4
5
6
7
8
9
android {
    buildFeatures {
        compose = true
    }

    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.13"
    }
}

然后再配置一坨依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
dependencies {
    val composeBom = platform("androidx.compose:compose-bom:2024.05.00")
    implementation(composeBom)

    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.ui:ui-graphics")

    // Material Design 3
    implementation("androidx.compose.material3:material3")

    // Android Studio Preview support
    implementation("androidx.compose.ui:ui-tooling-preview")
    debugImplementation("androidx.compose.ui:ui-tooling")
}

为了方便管理Compose依赖的版本,谷歌搞了一个叫做『物料清单』(Bill of Materials BOM),简单来说就是把Compose所有library的版本放到一个叫做BOM的library中,我们只需要指定一个BOM,这样,就能指定一坨Compose libraries的版本。详细的内容以及困难解决可以参考官方文档

理解Compose的基本原理

从我们的『HelloCompose』中可以看出Compose的特点,它是纯代码,Compose就是一个坨函数声明,不用再撸XML了;它是声明式的,也就是说你只是告诉框架需要什么,期望的样子是什么;它是响应式的,也就是说拿到最新的数据和状态,然后用相应的UI元素进行展示。这与以往用XML写UI是完全不同的,用XML是命令式的,你要拿到View,设置具体的细节。

用Compose撸UI主要分为两部分,一是元素,如布局和具体的渲染元素如文字图片;另一个则是样式控制,所有元素都能接受一个Modifier对象来控制元素的样式,如大小,位置,偏移,对齐等等。会在后面的文章中对这些概念进行详细的讨论。

另外需要注意,Compose就是一坨函数,上面例子中看到的『setContent』,『HelloComposeTheme』,『Suface』,『 Greeting』,『GreetingPreview』,『Box』,『Text』都是函数,虽然它们不符合Kotlin的函数命令规范。这里面套娃式的结构如:

1
2
3
4
5
6
7
8
9
10
11
setContent {
    HelloComposeTheme {
        // A surface container using the 'background' color from the theme
        Surface(
            modifier = Modifier.fillMaxSize(),
            color = MaterialTheme.colorScheme.background
        ) {
             Greeting("Android with Compose!")
        }
   }
}

是借助于尾部lambda实现的内部DSL,本质上也都是函数调用,视为函数调用就好了。感觉不熟悉的同学可以看看前面的文章以加深理解。

为啥要使用Compose

就Android开发来说明明已经有比较完善的View和XML来撸UI,为啥还要搞一个Compose呢?

首先,声明式编程范式是最新式的UI构建方式,较原始方式(View和XML)它更加接近于人的思维。开发者只需要告诉架构『我要什么』以及『该如何响应』就可以了,其他事情都交给框架。像Flutter, React, SwiftUI等都是声明式的。一旦我们熟悉了以后,就会发现声明式UI可以极大的提高开发效率,最重要的是它能提高可扩展性(Scalability)。

再有,Compose与各种最新的libraries粘合的特别好,像JetpackMaterialDesign等等,都可以直接在Compose中使用,非常的方便。

最后,最重要的原因是Google在大力的布道Compose,已经把Compose设置为默认的UI开发方式,作为MAD(Modern Android Development)的一块拼盘,新推出的有关于UI的文章都是基于Compose的。并且Google还在不断大力开发Compose,推出新功能以及提升渲染性能。从前面的例子也可以看出,现在默认新建一个项目就是用的Compose,相反,如果想要弄一个只用View的项目,还比较麻烦,要去除一系列配置参数。

作为开发者,肯定要顺应潮流,迎头敢上(对的,是敢而不是赶)。

迁移建议

Compose虽然新式且好用,但我们在做迁移的时候要谨慎。对于新的技术(无论是新的编程语言,新的框架,还是新的编程范式)切忌不要一刀切或者搞大跃进。对于,纯新的功能,或者说纯新的项目,当然可以直接就用Compose来开发;但是对于现有的功能,暂时不要去动它,万不可上来就想着用Compose重写一遍。等到对Compose比较熟悉了,人力较富余时,以及现在功能仍会有新的较大的改动时才考虑去重写。对于比较成熟且稳定的功能,建议就不要去折腾它了,因为不会带来价值和收益。

官方也有迁移建议,可以看一看。

优质教程与实例

Google对Compose还是很上心的,写了大量的文档,此外还有很多教程(CodeLabs),以及很多Demo app。并且Compose作为MAD的一块拼盘,也融合进了MAD里面,特别是架构层面的文章中用的都是Compose。

未完,待续

本文从快速上手的Demo开始,解释一些核心概念,并给出一些有用的资源链接。相信通过此文,能对Compose有一个很好的了解。后续会继续深入探讨各个话题,以练成降Compose十八掌!

Comments