Compose 基础:理念和架构

1. 引言

随着Android开发的不断演进,Google为我们带来了Jetpack Compose——一个用于构建UI的新框架。你可能已经听说过它,并且会有一些疑问:“它与我们已经熟悉的传统方式有什么不同?我需要重新学习所有东西吗?”别担心,Jetpack Compose虽然引入了一些新概念,但它的目标其实是让开发更加简洁高效。

Compose是基于“声明式编程”理念的UI框架,这个词听起来可能有些复杂,但它的本质其实很简单:与其告诉程序每一步该怎么做(命令式),我们只需告诉它界面“应该是什么样子”,剩下的事情交给框架来处理。在你熟悉了这个新方式后,构建UI的过程会感觉更加直观,也更容易维护。

本文的目的:让从未接触过声明式开发的 Android 工程师也能简单的理解声明式和 Compose。

2. 传统开发与Jetpack Compose的区别

在进入Jetpack Compose之前,我们先简单回顾一下Android传统UI开发的方式。你可能已经习惯了使用XML来定义布局,通过findViewById来获取UI元素,之后在Java或Kotlin代码里对这些元素进行操作。这种方式被称为“命令式编程”,因为我们需要一步步告诉系统如何创建界面和更新界面。

例如,假设你有一个按钮和一段文字,当用户点击按钮时,文字内容需要更新。传统开发方式的代码可能是这样的:

传统的Android开发方式(命令式编程)

XML布局文件:

android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">

  

Activity代码:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button: Button = findViewById(R.id.button)
        val textView: TextView = findViewById(R.id.textView)

        button.setOnClickListener {
            textView.text = "Hello, Android!"
        }
    }
}

在这个例子中,我们使用了XML来定义界面布局,然后通过findViewById找到按钮和TextView,并设置点击事件。每一步都需要明确地告诉系统该如何操作。

Jetpack Compose方式(声明式编程)

而在Jetpack Compose中,你可以直接在代码中声明整个UI,并且不需要findViewById,也不需要手动管理UI状态。Compose会根据状态的变化自动更新UI。以下是用Compose实现相同功能的代码:

@Composable
fun MyScreen() {
    var text by remember { mutableStateOf("Hello World") }

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Button(onClick = { text = "Hello, Compose!" }) {
            Text("Click Me")
        }
        Text(text = text)
    }
}

@Preview(showBackground = true) 
@Composable
fun PreviewMyScreen() {
    MyScreen()
}

在这个例子中,ButtonText都是Compose内置的组件,remembermutableStateOf用于管理状态。当按钮被点击时,text的值会更新,Compose会自动重新渲染UI。你不需要手动更新TextView,所有的UI更新都由Compose根据状态变化来处理。

通过这个例子可以看到,Jetpack Compose的代码更加简洁明了。我们直接声明了界面应该显示什么内容,以及当用户交互时状态如何变化,省去了繁琐的UI管理逻辑。

3. Jetpack Compose的核心概念

Jetpack Compose的核心理念是声明式UI编程,它让你通过描述界面的“状态”来构建UI,避免了手动操作界面的具体逻辑。在这里,我们将介绍几个关键的核心概念,帮助你快速理解Compose的设计哲学。

3.1 Composable函数

Compose最重要的一个概念是“可组合函数”(Composable Functions)。这些函数就是你用来创建UI元素的基本单元。任何可以渲染到屏幕上的内容(例如按钮、文本、图像)都是通过@Composable注解的函数实现的。

示例:

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

这个Greeting函数是一个简单的Composable,它接受一个name参数,并将其显示在一个Text组件中。注意,所有用@Composable标记的函数都是没有返回值的,因为它们负责描述界面而不是返回具体的对象。

3.2 状态驱动 UI

Compose的另一个核心理念是“状态驱动的UI”。传统开发中,你可能需要手动更新视图的内容,但在Compose中,UI是自动根据状态变化而更新的。

Compose通过“状态”来管理UI内容的变化,使用状态(State)管理不同的UI元素。状态可以是某个变量,当这个变量改变时,Compose会自动重新渲染界面。你只需要专注于描述“当状态发生变化时,界面应该是什么样子”。

示例:

@Composable
fun ClickCounter() {
    var count by remember { mutableStateOf(0) }

    Button(onClick = { count++ }) {
        Text(text = "Clicked $count times")
    }
}

在这个例子中,count变量就是UI的状态。每当按钮被点击时,count的值会增加,Button内部的文字会自动更新,无需你手动刷新界面。

3.3 可组合性

Compose强调“可组合性”(Composability)。换句话说,Compose鼓励你将UI拆解成一系列可重用的小部件(Composable),这样可以让你的UI代码更加简洁和模块化。

例如,你可以将一个大的屏幕拆解成多个小的组件,每个组件专注于一个具体功能:

示例:

@Composable
fun ScreenContent() {
    Column {
        Greeting(name = "Compose")
        ClickCounter()
    }
}

在这个例子中,我们将之前的GreetingClickCounter组合在一起,形成一个完整的界面。你可以通过组合小的Composable函数来构建复杂的UI。

3.4 Recomposition/Recompose(重组)

Compose的另一个强大之处在于“重组”(Recomposition)。当状态发生变化时,Compose会只重新绘制那些受影响的部分,而不是整个界面。这极大地提高了UI更新的效率,也让代码的逻辑更加清晰。

例如,当你在ClickCounter中点击按钮时,Compose只会重新绘制按钮和计数相关的部分,而不会重新绘制其他不相关的部分。

4. Jetpack Compose的优势

Jetpack Compose并不是为了让开发者学更多的新概念,而是为了让我们从繁琐的UI更新操作中解放出来。很多开发者在刚接触Compose时可能会有疑问:“这真的能提升效率吗?”答案是肯定的。下面列出几个实际的优势,你可能会在实际项目中迅速感受到。

4.1 状态管理更直观

Compose最大的改变之一是它的状态驱动UI模式。在传统的Android开发中,当某个UI元素需要更新时,你必须找到对应的控件,通过findViewById或其他方式,然后手动调用更新方法。而在Compose中,UI是自动根据状态的变化更新的。你只需要定义好当状态发生变化时UI应该呈现的样子,框架会自动处理底层逻辑。比如你可以用简单的代码展示一段状态变化后的文字,而不需要担心每次手动去刷新界面。

4.2 组件化和可重用性更强

在Compose中,每个UI组件都是一个独立的Composable函数,这让代码的可重用性得到了极大的提升。你可以轻松地将界面分解为更小的组件,然后在不同的地方组合使用,不必每次都从头定义。这不仅让开发更清晰,还提高了代码的可维护性。例如,你可以创建一个按钮组件,然后在多个不同的界面中复用它,而不需要复制粘贴布局代码。

4.3 布局和样式更灵活

Compose的Modifier系统提供了一个强大而灵活的方式来定制UI组件的外观和行为。你可以通过链式调用来组合不同的Modifier,实现布局、尺寸、对齐方式等各种效果,而不需要再编写额外的样式文件或嵌套过多的布局。它的灵活性极大地减少了UI布局的复杂度,使得UI设计更加简洁、直观。

4.4 预览功能提升开发体验

Jetpack Compose提供了实时预览功能,你可以在Android Studio中立即看到UI的变化效果,而不需要像以前那样频繁编译和运行应用。这对于开发者来说是一个巨大的提升,特别是在迭代UI设计时,可以快速验证自己的想法。

4.5 性能更高效

由于Compose是从零开始设计的,它采用了全新的渲染机制,性能更高效。在传统的Android开发中,复杂的UI结构可能会影响应用性能,但Compose通过减少不必要的UI更新以及智能化的Recomposition机制,确保了UI的响应速度和流畅性。

5. 实践:构建一个简单的交互界面

我们来实现一个可以动态添加元素的列表,通过Jetpack Compose的状态管理和交互逻辑,让界面自动响应用户的点击操作。

代码示例:动态列表与按钮交互
@Composable
fun ListDemo() {
   val items = remember { mutableStateListOf("Item 1", "Item 2", "Item 3") }

    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Button(onClick = {
            items.add("New Item ${items.size + 1}")
        }) {
            Text(text = "Add Item")
        }
        Spacer(modifier = Modifier.height(16.dp))

        LazyColumn {
            items(items) { item ->
                Text(text = item, modifier = Modifier.padding(16.dp))
            }
        }
    }
}

解释

  1. 动态列表:使用mutableStateListOf来管理列表项,这样可以确保列表在状态改变时自动触发UI重绘。
  2. LazyColumn组件:用于高效地显示列表项,即使列表很长也能保持流畅。
  3. 状态驱动的UI更新:每次点击“Add Item”按钮,列表会添加一个新项,并立即更新界面。
  4. 简单布局:通过ColumnButton等组件来构建界面,确保布局整齐。

这个例子展示了如何用Compose实现简单的交互和状态管理,代码简洁直观,状态管理流畅。

代码示例:复杂的列表

来个稍微复杂点的例子?

一个界面根布局是个上下滑动的列表,其中的 Item 有 Linear、Grid、Horizontal Scroll 等等,传统的方式是使用 RecyclerView 的多 Item 功能写各种的 ViewHolder 拼接在一起,想想就可以知道会有多少的文件和代码。但是在 Compose 一切都变得简单了。

@Preview 
@Composable 
fun ComplexListDemo() {
    val items = remember { listOf("Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6") }

    LazyVerticalGrid(
        modifier = Modifier.fillMaxSize(),
        columns = GridCells.Fixed(2),
        verticalArrangement = Arrangement.spacedBy(10.dp),
        horizontalArrangement = Arrangement.spacedBy(10.dp)
    ) {
        item(span = { GridItemSpan(2) }) {
            Text(text = "Grid Section")
        }

        items(count = 4, span = { GridItemSpan(1) }) { index ->
            Text(
                text = "List Item $index",
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(16.dp)
                    .background(MaterialTheme.colorScheme.surface)
                    .padding(16.dp)
            )
        }

        item(span = { GridItemSpan(2) }) {
            Text(text = "Horizontal Scroll Section")
        }

        item(span = { GridItemSpan(2) }) {
            LazyRow(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.spacedBy(8.dp),
                contentPadding = PaddingValues(8.dp)
            ) {
                items(items) { item ->
                    Box(
                        modifier = Modifier
                            .background(MaterialTheme.colorScheme.secondary)
                            .padding(16.dp)
                            .width(120.dp)
                            .height(120.dp),
                        contentAlignment = Alignment.Center
                    ) {
                        Text(text = item, color = Color.White)
                    }
                }
            }
        }

        item(span = { GridItemSpan(2) }) {
            Text(text = "Linear Section")
        }

        items(count = 3, span = { GridItemSpan(2) }) { index ->
            Text(
                text = "List Item $index",
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(16.dp)
                    .background(MaterialTheme.colorScheme.surface)
                    .padding(16.dp)
            )
        }

    }
}

只需要以上 Compose 代码就可以实现复杂的界面样式。界面预览:

6. 总结

Jetpack Compose不是一个简单的UI工具,而是一种全新的编程思维方式。它的声明式编程模式让UI更新变得更加自然,通过状态驱动的方式自动处理界面重绘,省去了手动更新UI的烦恼。通过将UI组件化,Compose还能帮助你轻松构建模块化、可重用的代码,减少项目复杂性。

当然,任何新的工具都有一个学习曲线,但在你习惯了Compose的工作方式后,你会发现它比传统的命令式开发更加直观、灵活,并且大大提升了开发效率。Jetpack Compose不仅仅是为了构建UI,它还能让你的代码逻辑更清晰,界面更新更高效。如果你还在犹豫是否要切换到Compose,不妨试着在一个小项目里使用它,体验一下它为Android开发带来的革新。

阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/archives/22062,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?