Jorgen's blog Jorgen's blog
首页
  • 平台架构
  • 混合式开发记录
  • 推送服务
  • 数据分析
  • 实时调度
  • 架构思想

    • 分布式
  • 编程框架工具

    • 编程语言
    • 框架
    • 开发工具
  • 数据存储与处理

    • 数据库
    • 大数据
  • 消息、缓存与搜索

    • 消息队列
    • 搜索与日志分析
  • 前端与跨端开发

    • 前端技术
    • Android
  • 系统与运维

    • 操作系统
    • 容器化与 DevOps
  • 物联网与安全

    • 通信协议
    • 安全
    • 云平台
newland
  • 关于我
  • 终身学习
  • 关于时间的感悟
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

jorgen

Love it, make mistakes, learn, keep grinding.
首页
  • 平台架构
  • 混合式开发记录
  • 推送服务
  • 数据分析
  • 实时调度
  • 架构思想

    • 分布式
  • 编程框架工具

    • 编程语言
    • 框架
    • 开发工具
  • 数据存储与处理

    • 数据库
    • 大数据
  • 消息、缓存与搜索

    • 消息队列
    • 搜索与日志分析
  • 前端与跨端开发

    • 前端技术
    • Android
  • 系统与运维

    • 操作系统
    • 容器化与 DevOps
  • 物联网与安全

    • 通信协议
    • 安全
    • 云平台
newland
  • 关于我
  • 终身学习
  • 关于时间的感悟
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Capacitor浅析
  • ADB调试
  • mlkit
  • face detection
  • Android中的Kotlin协程:告别回调地狱
  • Android性能优化实践与技巧
  • Android Jetpack Compose入门:构建现代UI的全新方式
  • Android Jetpack Compose入门与实践 - 构建现代Android UI
  • Android Jetpack Compose入门指南 - 构建现代UI的全新方式
  • Android Jetpack与架构组件-构建现代化应用
  • Android Jetpack架构组件:ViewModel与LiveData实战指南
  • Android Jetpack组件:构建现代Android应用的核心利器
  • Android Jetpack组件详解:构建现代化应用的核心
  • Android数据绑定与MVVM架构-构建现代化应用
    • 前言
    • MVVM架构概述
      • MVVM的核心组件
      • MVVM的优势
    • Android数据绑定框架
      • 什么是数据绑定?
      • 数据绑定的基本设置
      • 基本数据绑定示例
    • 实践:构建完整的MVVM应用
      • 1. 创建数据模型(Model)
      • 2. 创建ViewModel
      • 3. 创建布局并使用数据绑定
      • 4. 创建Activity
    • 高级数据绑定技巧
      • 自定义绑定适配器
      • 双向数据绑定
      • 使用表达式
    • MVVM架构的最佳实践
      • 1. 遵循单一职责原则
      • 2. 使用依赖注入
      • 3. 处理配置变更
      • 4. 使用协程处理异步操作
      • 5. 使用LiveData或StateFlow
    • 结语
  • Android架构组件:构建现代化应用的基石
  • Android架构组件与Jetpack-构建现代化应用的基石
  • Android架构组件与Jetpack-构建现代化应用的基础
  • Android架构设计之MVVM模式实战指南
  • 拥抱未来:Android Jetpack Compose入门指南
  • Android权限管理完全指南-从基础到实践
  • Android测试指南-从单元测试到UI测试的实践之路
  • Android依赖注入实战:从Dagger到Hilt的进化之路
  • Android网络编程完全指南-从HTTP到Retrofit的实践之路
  • Android数据持久化完全指南-从SharedPreferences到Room数据库
  • Android多线程与并发处理完全指南-从Thread到协程的进阶之路
  • Android应用打包与发布全流程指南-从签名到上架的实战之路
  • Android安全完全指南-从基础防护到高级加密的实战之路
  • android
Jorgen
2023-11-15
目录

Android数据绑定与MVVM架构-构建现代化应用

# 前言

在Android应用开发的世界里,随着应用复杂度的增加,如何构建一个可维护、可测试且易于扩展的应用架构变得尤为重要。我曾经在一个项目中直接把所有逻辑都写在Activity里,结果后来修改一个简单功能竟然要翻找几百行代码,简直是噩梦!

幸运的是,Google推出的MVVM(Model-View-ViewModel)架构模式为我们提供了一种优雅的解决方案。而Android数据绑定框架更是如虎添翼,让我们能够以声明式的方式连接UI和数据。

提示

MVVM架构模式将应用程序分为三个主要部分:模型(Model)、视图(View)和视图模型(ViewModel)。这种分离使得UI逻辑与业务逻辑解耦,提高了代码的可测试性和可维护性。

本文将带你深入了解Android数据绑定与MVVM架构,从基础概念到实际应用,助你构建更专业的Android应用。

# MVVM架构概述

# MVVM的核心组件

MVVM架构包含三个核心组件:

  1. Model(模型):负责处理数据和业务逻辑,通常包括数据源、数据模型和业务逻辑处理。

  2. View(视图):负责UI展示和用户交互,在Android中通常指Activity、Fragment和XML布局文件。

  3. ViewModel(视图模型):作为View和Model之间的桥梁,处理View的业务逻辑,但不持有任何View的引用。

# MVVM的优势

  • 关注点分离:UI逻辑与业务逻辑分离,各司其职
  • 可测试性:ViewModel不依赖于View,可以轻松进行单元测试
  • 可维护性:代码结构清晰,易于理解和修改
  • 生命周期感知:ViewModel能够感知组件生命周期,避免内存泄漏

# Android数据绑定框架

# 什么是数据绑定?

Android数据绑定框架是一个支持库,允许你以声明式的方式将UI组件绑定到数据源。这意味着你可以在XML布局文件中直接绑定数据,而无需在Activity或Fragment中编写大量的findViewById代码。

# 数据绑定的基本设置

首先,在app模块的build.gradle文件中启用数据绑定:

android {
    ...
    buildFeatures {
        dataBinding true
    }
}
1
2
3
4
5
6

# 基本数据绑定示例

假设我们有一个简单的用户信息显示界面:

<!-- activity_user.xml -->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="user"
            type="com.example.User" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".UserActivity">

        <TextView
            android:id="@+id/tvName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.name}"
            android:textSize="18sp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginTop="32dp"/>

        <TextView
            android:id="@+id/tvEmail"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.email}"
            android:textSize="16sp"
            app:layout_constraintTop_toBottomOf="@id/tvName"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginTop="16dp"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
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

在Activity中使用:

class UserActivity : AppCompatActivity() {
    private lateinit var binding: ActivityUserBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // 初始化数据绑定
        binding = DataBindingUtil.setContentView(this, R.layout.activity_user)
        
        // 创建用户对象
        val user = User("张三", "zhangsan@example.com")
        
        // 将用户对象设置给布局
        binding.user = user
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 实践:构建完整的MVVM应用

让我们通过一个实际的例子来展示如何结合数据绑定和MVVM架构构建一个完整的应用。

# 1. 创建数据模型(Model)

// User.kt
data class User(
    val id: Long,
    val name: String,
    val email: String,
    val avatarUrl: String
)
1
2
3
4
5
6
7

# 2. 创建ViewModel

// UserViewModel.kt
class UserViewModel : ViewModel() {
    private val _user = MutableLiveData<User>()
    val user: LiveData<User> = _user

    init {
        // 模拟从网络或数据库加载数据
        loadUser()
    }

    private fun loadUser() {
        viewModelScope.launch {
            // 模拟网络请求延迟
            delay(1000)
            
            // 更新用户数据
            _user.value = User(
                id = 1,
                name = "李四",
                email = "lisi@example.com",
                avatarUrl = "https://example.com/avatar.jpg"
            )
        }
    }
}
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

# 3. 创建布局并使用数据绑定

<!-- activity_user_profile.xml -->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="viewModel"
            type="com.example.UserViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".UserProfileActivity">

        <ImageView
            android:id="@+id/ivAvatar"
            android:layout_width="100dp"
            android:layout_height="100dp"
            app:imageUrl="@{viewModel.user.avatarUrl}"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginTop="32dp"/>

        <TextView
            android:id="@+id/tvName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{viewModel.user.name}"
            android:textSize="24sp"
            android:textStyle="bold"
            app:layout_constraintTop_toBottomOf="@id/ivAvatar"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginTop="16dp"/>

        <TextView
            android:id="@+id/tvEmail"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{viewModel.user.email}"
            android:textSize="18sp"
            app:layout_constraintTop_toBottomOf="@id/tvName"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginTop="8dp"/>

        <ProgressBar
            android:id="@+id/progressBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:visibility="@{viewModel.user == null ? View.VISIBLE : View.GONE}"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
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

# 4. 创建Activity

// UserProfileActivity.kt
class UserProfileActivity : AppCompatActivity() {
    private lateinit var binding: ActivityUserProfileBinding
    private val viewModel: UserViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // 初始化数据绑定
        binding = DataBindingUtil.setContentView(this, R.layout.activity_user_profile)
        
        // 设置ViewModel
        binding.viewModel = viewModel
        
        // 设置生命周期所有者,使LiveData能够自动更新UI
        binding.lifecycleOwner = this
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 高级数据绑定技巧

# 自定义绑定适配器

数据绑定框架允许我们创建自定义的绑定适配器,以便在XML中使用自定义属性。例如,我们可以创建一个适配器来加载网络图片:

// BindingAdapters.kt
@BindingAdapter("imageUrl")
fun setImageUrl(imageView: ImageView, url: String?) {
    url?.let {
        // 使用Glide或Picasso加载图片
        Glide.with(imageView.context)
            .load(url)
            .into(imageView)
    }
}
1
2
3
4
5
6
7
8
9
10

然后在XML中使用:

<ImageView
    android:id="@+id/ivAvatar"
    android:layout_width="100dp"
    android:layout_height="100dp"
    app:imageUrl="@{user.avatarUrl}" />
1
2
3
4
5

# 双向数据绑定

数据绑定框架还支持双向数据绑定,使UI能够同时显示和更新数据。例如,我们可以创建一个双向绑定的EditText:

<EditText
    android:id="@+id/etName"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@={user.name}" />
1
2
3
4
5

注意@={}语法中的等号,这表示双向绑定。

# 使用表达式

数据绑定支持在XML中使用表达式,例如:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.age > 18 ? 成年 : 未成年人}"
    android:visibility="@{user.isAdmin ? View.VISIBLE : View.GONE}" />
1
2
3
4
5

# MVVM架构的最佳实践

# 1. 遵循单一职责原则

每个类应该只有一个改变的理由。ViewModel只负责处理UI相关的逻辑,不直接处理数据获取或存储。

# 2. 使用依赖注入

推荐使用Hilt或Dagger等依赖注入框架来管理ViewModel和其他依赖项的生命周期。

# 3. 处理配置变更

ViewModel默认会 survived 配置变更(如屏幕旋转),但需要注意在onCleared()中清理资源。

# 4. 使用协程处理异步操作

在ViewModel中使用协程处理网络请求、数据库操作等异步任务,避免阻塞主线程。

class UserViewModel : ViewModel() {
    private val _users = MutableLiveData<List<User>>()
    val users: LiveData<List<User>> = _users

    fun loadUsers() {
        viewModelScope.launch {
            try {
                val users = userRepository.getUsers()
                _users.value = users
            } catch (e: Exception) {
                // 处理错误
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 5. 使用LiveData或StateFlow

使用LiveData或StateFlow来观察数据变化,并在UI层响应这些变化。

# 结语

通过本文,我们深入了解了Android数据绑定与MVVM架构的核心概念和实践方法。MVVM架构模式为我们提供了一种清晰、可测试的应用结构,而数据绑定框架则简化了UI与数据之间的连接。

🏗 构建一个良好的架构需要时间和实践,不要期望一蹴而就。从简单的项目开始尝试,逐步应用到更复杂的应用中。

记住,架构不是目的而是手段。选择最适合你项目需求的架构,而不是盲目追随潮流。随着经验的积累,你会找到最适合自己团队的架构模式。

希望本文能够帮助你更好地理解和应用Android数据绑定与MVVM架构,构建出更专业、更高质量的Android应用!🚀

"代码是写给人看的,顺便能在机器上运行。"

  • 哈罗德·艾贝尔森
#MVVM#数据绑定#架构设计#Kotlin
上次更新: 2026/01/28, 10:42:53
Android Jetpack组件详解:构建现代化应用的核心
Android架构组件:构建现代化应用的基石

← Android Jetpack组件详解:构建现代化应用的核心 Android架构组件:构建现代化应用的基石→

最近更新
01
LLM
01-30
02
intro
01-30
03
intro
01-30
更多文章>
Theme by Vdoing | Copyright © 2019-2026 Jorgen | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式