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架构-构建现代化应用
  • Android架构组件:构建现代化应用的基石
    • 前言
    • 什么是Android架构组件?
    • ViewModel:拯救你的数据
    • LiveData:响应式数据的桥梁
    • Room:持久化的得力助手
      • 定义实体
      • 定义DAO(数据访问对象)
      • 创建数据库
      • 在ViewModel中使用Room
    • Navigation:简化导航逻辑
      • 创建导航图
      • 在Activity中使用Navigation
    • 实战:MVVM架构模式
      • 1. Model层(数据层)
      • 2. ViewModel层
      • 3. View层(UI层)
      • 4. ViewModelFactory(可选)
    • 常见问题与解决方案
      • 问题1:如何在ViewModel中获取Context?
      • 问题2:如何处理多个观察者?
      • 问题3:如何处理网络请求错误?
    • 结语
  • 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架构组件:构建现代化应用的基石

# 前言

作为一名Android开发者,你是否曾经面临过这样的困境:随着应用功能的不断增加,代码变得越来越难以维护;Activity/Fragment中的逻辑过于臃肿,难以测试;数据在UI层和业务层之间传递时变得混乱;或者配置更改(如屏幕旋转)导致数据丢失?

我曾经也深陷这些"泥潭"中,直到我开始深入理解并实践Android架构组件。🏗️ 这些组件不仅仅是工具,更是一种思维方式,它们帮助我们构建更加健壮、可维护且可测试的Android应用。

今天,我想和大家分享这些"秘密武器",看看它们如何彻底改变我们的开发体验。

# 什么是Android架构组件?

Android架构组件是Google推出的一套库,旨在帮助开发者设计出健壮、可测试且可维护的应用。这些组件遵循推荐的应用架构模式,解决了Android开发中的常见问题。

提示

架构组件是Jetpack的一部分,Jetpack是Google推出的一套库、工具和指南,旨在帮助开发者更快地构建高质量的应用。

核心架构组件主要包括:

  • ViewModel:在配置更改后存活,并管理UI相关的数据
  • LiveData:可观察的数据持有者类,遵循观察者模式
  • Room:一个SQLite对象映射库
  • Navigation:处理应用内导航的框架
  • Data Binding:声明性地将UI组件绑定到数据源
  • WorkManager:调度可保证会运行的后台任务
  • Paging Library:帮助分页加载数据

# ViewModel:拯救你的数据

在ViewModel出现之前,我们通常会在Activity或Fragment中保存数据,但这种方式在配置更改(如屏幕旋转)时会导致数据丢失。

// 错误的做法
class MainActivity : AppCompatActivity() {
    private var data: String? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        // 屏幕旋转后,data会被重置为null
        data = "重要数据"
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

ViewModel专门解决这个问题,它会在配置更改后继续存活:

class MyViewModel : ViewModel() {
    private val _data = MutableLiveData<String>()
    val data: LiveData<String> = _data
    
    init {
        _data.value = "重要数据"
    }
}

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: MyViewModel
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
        
        // 观察数据变化
        viewModel.data.observe(this) { newData ->
            // 更新UI
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

ViewModel的优势:

  1. 配置更改时数据不丢失:ViewModel不会因配置更改而被销毁
  2. 生命周期感知:自动与Activity/Fragment的生命周期绑定
  3. 测试友好:可以轻松地单独测试ViewModel逻辑,而不需要UI组件

# LiveData:响应式数据的桥梁

LiveData是一个可观察的数据持有者类,但它与普通的观察者模式不同,它是生命周期感知的。

class MyViewModel : ViewModel() {
    private val _userName = MutableLiveData<String>()
    val userName: LiveData<String> = _userName
    
    fun loadUser() {
        // 模拟网络请求
        viewModelScope.launch {
            val name = withContext(Dispatchers.IO) {
                // 网络请求逻辑
                "张三"
            }
            _userName.value = name
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

在Activity中使用LiveData:

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: MyViewModel
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
        
        // 只有当Activity处于活跃状态时才会接收更新
        viewModel.userName.observe(this) { name ->
            textView.text = name
        }
        
        viewModel.loadUser()
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

LiveData的特点:

  1. 生命周期感知:只有在LifecycleOwner(如Activity/Fragment)处于活跃状态时才会更新UI
  2. 数据一致性:在配置更改后,会立即将最新值发送给新的观察者
  3. 防止内存泄漏:自动清理观察者引用
  4. UI更新线程安全:确保在主线程更新UI

# Room:持久化的得力助手

Room提供了一个SQLite抽象层,让你能够在更少的代码下更轻松地使用SQLite数据库。

# 定义实体

@Entity(tableName = "users")
data class User(
    @PrimaryKey val id: Int,
    @ColumnInfo(name = "name") val name: String,
    @ColumnInfo(name = "age") val age: Int
)
1
2
3
4
5
6

# 定义DAO(数据访问对象)

@Dao
interface UserDao {
    @Query("SELECT * FROM users")
    fun getAllUsers(): LiveData<List<User>>
    
    @Insert
    suspend fun insertUser(user: User)
    
    @Update
    suspend fun updateUser(user: User)
    
    @Delete
    suspend fun deleteUser(user: User)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 创建数据库

@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
    
    companion object {
        @Volatile
        private var INSTANCE: AppDatabase? = null
        
        fun getDatabase(context: Context): AppDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "app_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 在ViewModel中使用Room

class UserViewModel : ViewModel() {
    private val userDao = AppDatabase.getDatabase(application).userDao()
    
    val allUsers: LiveData<List<User>> = userDao.getAllUsers()
    
    fun insertUser(user: User) {
        viewModelScope.launch(Dispatchers.IO) {
            userDao.insertUser(user)
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11

Room的优势:

  1. 编译时验证:在编译时检查SQL查询
  2. 简化数据库迁移:提供迁移支持
  3. 与LiveData完美集成:自动将数据库变化转换为LiveData流
  4. 协程支持:可以使用协程执行数据库操作

# Navigation:简化导航逻辑

Navigation组件帮助您实现应用内的导航,处理Fragment之间的转换,以及处理深层链接。

# 创建导航图

<?xml version="1.0" encoding="utf-8"?>
<navigation 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"
    android:id="@+id/nav_graph"
    app:startDestination="@id/firstFragment">

    <fragment
        android:id="@+id/firstFragment"
        android:name="com.example.FirstFragment"
        android:label="fragment_first"
        tools:layout="@layout/fragment_first" >
        <action
            android:id="@+id/action_firstFragment_to_secondFragment"
            app:destination="@id/secondFragment" />
    </fragment>

    <fragment
        android:id="@+id/secondFragment"
        android:name="com.example.SecondFragment"
        android:label="fragment_second"
        tools:layout="@layout/fragment_second" />
</navigation>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 在Activity中使用Navigation

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        val navController = findNavController(R.id.nav_host_fragment)
        
        // 设置ActionBar与Navigation的联动
        appBarConfiguration = AppBarConfiguration(navController.graph)
        setupActionBarWithNavController(navController, appBarConfiguration)
    }
    
    override fun onSupportNavigateUp(): Boolean {
        val navController = findNavController(R.id.nav_host_fragment)
        return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

Navigation的优势:

  1. 可视化编辑器:提供直观的拖放界面设计导航流程
  2. 类型安全的深链接:使用安全ID进行导航,避免硬编码字符串
  3. 动画和过渡效果:内置支持页面切换动画
  4. 处理复杂导航:轻松处理回栈参数和传递数据

# 实战:MVVM架构模式

结合上述组件,我们可以构建一个标准的MVVM(Model-View-ViewModel)架构:

# 1. Model层(数据层)

// User.kt - 实体
@Entity(tableName = "users")
data class User(
    @PrimaryKey val id: Int,
    @ColumnInfo(name = "name") val name: String
)

// UserDao.kt - DAO
@Dao
interface UserDao {
    @Query("SELECT * FROM users")
    fun getAllUsers(): LiveData<List<User>>
    
    @Insert
    suspend fun insertAll(users: List<User>)
}

// AppDatabase.kt - 数据库
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 2. ViewModel层

class UserViewModel(private val userDao: UserDao) : ViewModel() {
    val users: LiveData<List<User>> = userDao.getAllUsers()
    
    fun loadUsers() {
        viewModelScope.launch {
            // 模拟网络请求
            val users = withContext(Dispatchers.IO) {
                // 这里可以调用Retrofit等网络库
                listOf(
                    User(1, "张三"),
                    User(2, "李四"),
                    User(3, "王五")
                )
            }
            // 保存到数据库
            userDao.insertAll(users)
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 3. View层(UI层)

class UserFragment : Fragment() {
    private lateinit var viewModel: UserViewModel
    
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_user, container, false)
    }
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        val userDao = AppDatabase.getDatabase(requireContext()).userDao()
        viewModel = ViewModelProvider(this, UserViewModelFactory(userDao)).get(UserViewModel::class.java)
        
        val adapter = UserAdapter()
        recyclerView.adapter = adapter
        
        // 观察数据变化
        viewModel.users.observe(viewLifecycleOwner) { users ->
            adapter.submitList(users)
        }
        
        // 加载数据
        viewModel.loadUsers()
    }
}
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

# 4. ViewModelFactory(可选)

class UserViewModelFactory(private val userDao: UserDao) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(UserViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return UserViewModel(userDao) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}
1
2
3
4
5
6
7
8
9

# 常见问题与解决方案

# 问题1:如何在ViewModel中获取Context?

ViewModel不应该直接持有Context引用,因为Context可能与View的生命周期相关,而ViewModel的生命周期更长。如果确实需要Context,可以通过以下方式:

class MyViewModel(application: Application) : AndroidViewModel(application) {
    private val context = application.applicationContext
    
    fun doSomethingWithContext() {
        // 使用context
    }
}
1
2
3
4
5
6
7

# 问题2:如何处理多个观察者?

LiveData默认只有一个活跃观察者,如果需要多个观察者,可以使用以下方法:

private val _data = MutableLiveData<String>()
val data: LiveData<String> = _data

// 或者使用MediatorLiveData
private val _result = MediatorLiveData<String>()
val result: LiveData<String> = _result

// 添加多个源
_result.addSource(source1) { value ->
    _result.value = value
}
_result.addSource(source2) { value ->
    _result.value = value
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 问题3:如何处理网络请求错误?

sealed class Result<out T> {
    data class Success<out T>(val data: T) : Result<T>()
    data class Error(val exception: Throwable) : Result<Nothing>()
    object Loading : Result<Nothing>()
}

class MyViewModel : ViewModel() {
    private val _result = MutableLiveData<Result<User>>()
    val result: LiveData<Result<User>> = _result
    
    fun loadUser() {
        _result.value = Result.Loading
        
        viewModelScope.launch {
            try {
                val user = withContext(Dispatchers.IO) {
                    // 网络请求
                    User(1, "张三")
                }
                _result.value = Result.Success(user)
            } catch (e: Exception) {
                _result.value = Result.Error(e)
            }
        }
    }
}
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

# 结语

Android架构组件不仅仅是一套工具,它们代表了一种构建高质量Android应用的思维方式。通过ViewModel、LiveData、Room等组件,我们可以轻松应对Android开发中的各种挑战。

从我个人的经验来看,采用架构组件后,我的代码变得更加清晰、可测试,而且更容易维护。特别是在团队协作中,统一的架构模式大大提高了开发效率和代码质量。

当然,架构组件也不是银弹,它们需要时间和实践来真正掌握。我建议从简单的ViewModel和LiveData开始,逐步深入到更复杂的组件如Room和Navigation。

最后,我想说的是,架构的选择应该基于项目需求和团队特点,而不是盲目追求最新的技术。找到适合自己团队的架构模式,才是最重要的。

"代码是写给人看的,顺便给机器执行。" —— 好的架构不仅让代码更易维护,也让开发者更有成就感。

希望这篇文章能帮助你更好地理解和使用Android架构组件。如果你有任何问题或建议,欢迎在评论区留言交流!👇

#Android#架构组件#Jetpack#MVVM#ViewModel#LiveData#Room
上次更新: 2026/01/28, 10:42:53
Android数据绑定与MVVM架构-构建现代化应用
Android架构组件与Jetpack-构建现代化应用的基石

← Android数据绑定与MVVM架构-构建现代化应用 Android架构组件与Jetpack-构建现代化应用的基石→

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