Android数据架构模式
1. 背景与演进历程
Android应用架构经历了从传统MVC到现代响应式模式的演变。早期Activity承担过多职责(视图+控制器),导致代码臃肿、难以测试。2017年Google推出https://developer.android.com/topic/architecture后,MVVM成为官方推荐模式,随后MVI等响应式模式逐渐兴起。
2. 核心架构模式详解
2.1 MVC模式(Model-View-Controller)
// Model层 - 数据模型
data class User(val name: String, val email: String)
// View层 - XML布局(省略)
// Controller层 - Activity/Fragment
class UserActivity : AppCompatActivity() {
private lateinit var textView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user)
textView = findViewById(R.id.text_view)
// 控制器直接操作模型和视图
val user = User("John", "john@example.com")
updateView(user)
}
private fun updateView(user: User) {
textView.text = "${user.name} - ${user.email}"
}
}
问题:Activity同时承担View和Controller职责,导致代码膨胀(God Activity问题)
2.2 MVP模式(Model-View-Presenter)
// Contract定义接口约束
interface UserContract {
interface View {
fun showUser(user: User)
fun showError(message: String)
}
interface Presenter {
fun loadUser()
}
}
// Presenter实现
class UserPresenter(
private val view: UserContract.View,
private val repository: UserRepository
) : UserContract.Presenter {
override fun loadUser() {
try {
val user = repository.getUser()
view.showUser(user)
} catch (e: Exception) {
view.showError(e.message ?: "Unknown error")
}
}
}
// View实现(Activity)
class UserActivity : AppCompatActivity(), UserContract.View {
private lateinit var presenter: UserPresenter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
presenter = UserPresenter(this, UserRepository())
presenter.loadUser()
}
override fun showUser(user: User) {
// 更新UI
}
override fun showError(message: String) {
// 显示错误
}
}
优势:视图与业务逻辑解耦,便于单元测试(Presenter可独立测试)
2.3 MVVM模式(Model-View-ViewModel)
// ViewModel
class UserViewModel : ViewModel() {
private val _user = MutableLiveData<User>()
val user: LiveData<User> = _user
private val _error = MutableLiveData<String>()
val error: LiveData<String> = _error
fun loadUser() {
viewModelScope.launch {
try {
val user = UserRepository().getUser()
_user.value = user
} catch (e: Exception) {
_error.value = e.message
}
}
}
}
// Activity/Fragment(View层)
class UserFragment : Fragment() {
private val viewModel: UserViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// 观察LiveData响应状态变化
viewModel.user.observe(viewLifecycleOwner) { user ->
binding.textView.text = "${user.name} - ${user.email}"
}
viewModel.error.observe(viewLifecycleOwner) { error ->
Toast.makeText(requireContext(), error, Toast.LENGTH_SHORT).show()
}
}
}
核心特性:
- 数据绑定(Data Binding):减少模板代码
- 生命周期感知:避免内存泄漏
- ViewModel保存UI状态:配置变更时数据不丢失
2.4 MVI模式(Model-View-Intent)
// 状态封装
data class UserState(
val user: User? = null,
val isLoading: Boolean = false,
val error: String? = null
)
// Intent(用户意图)
sealed class UserIntent {
object LoadUser : UserIntent()
data class UpdateUser(val name: String) : UserIntent()
}
// ViewModel处理状态流转
class UserViewModel : ViewModel() {
private val _state = MutableStateFlow(UserState())
val state: StateFlow<UserState> = _state
fun processIntent(intent: UserIntent) {
when (intent) {
is UserIntent.LoadUser -> loadUser()
is UserIntent.UpdateUser -> updateUser(intent.name)
}
}
private fun loadUser() {
_state.update { it.copy(isLoading = true) }
viewModelScope.launch {
try {
val user = UserRepository().getUser()
_state.update { it.copy(user = user, isLoading = false) }
} catch (e: Exception) {
_state.update { it.copy(error = e.message, isLoading = false) }
}
}
}
}
单向数据流特性:
- 用户操作 → Intent → ViewModel
- ViewModel处理 → 更新State
- State变化 → 触发UI更新
3. 数据层设计最佳实践
3.1 仓库模式(Repository Pattern)
class UserRepository(
private val localDataSource: UserLocalDataSource,
private val remoteDataSource: UserRemoteDataSource
) {
suspend fun getUser(): User {
// 优先返回缓存数据
val localUser = localDataSource.getUser()
if (localUser != null) {
return localUser
}
// 网络请求并缓存
val remoteUser = remoteDataSource.getUser()
localDataSource.saveUser(remoteUser)
return remoteUser
}
}
3.2 数据源隔离策略
4. 现代架构组件生态体系
4.1 Jetpack组件整合
// 使用Room持久化数据
@Entity
data class User(
@PrimaryKey val id: Int,
@ColumnInfo(name = "name") val name: String,
@ColumnInfo(name = "email") val email: String
)
@Dao
interface UserDao {
@Query("SELECT * FROM user")
fun getUsers(): Flow<List<User>>
}
// 使用WorkManager处理后台任务
class UploadWorker(appContext: Context, params: WorkerParameters) :
Worker(appContext, params) {
override fun doWork(): Result {
return try {
// 执行上传操作
Result.success()
} catch (e: Exception) {
Result.failure()
}
}
}
4.2 依赖注入(Dagger/Hilt)
@Module
@InstallIn(ViewModelComponent::class)
object AppModule {
@Provides
fun provideUserRepository(): UserRepository {
return UserRepositoryImpl()
}
}
@HiltViewModel
class UserViewModel @Inject constructor(
private val repository: UserRepository
) : ViewModel() { /* ... */ }
5. 测试策略
5.1 ViewModel单元测试
@RunWith(JUnit4::class)
class UserViewModelTest {
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
private lateinit var viewModel: UserViewModel
private val mockRepository = mock<UserRepository>()
@Before
fun setup() {
viewModel = UserViewModel(mockRepository)
}
@Test
fun `loadUser should update state with user data`() = runTest {
// 准备模拟数据
val testUser = User("Test", "test@example.com")
whenever(mockRepository.getUser()).thenReturn(testUser)
// 执行操作
viewModel.loadUser()
// 验证状态更新
assertEquals(testUser, viewModel.state.value.user)
}
}
5.2 UI测试(Espresso)
@RunWith(AndroidJUnit4::class)
class UserActivityTest {
@get:Rule
val activityRule = ActivityScenarioRule(UserActivity::class.java)
@Test
fun shouldDisplayUserData() {
// 模拟数据
val testUser = User("Test", "test@example.com")
// 验证UI显示
onView(withId(R.id.text_name)).check(matches(withText(testUser.name)))
onView(withId(R.id.text_email)).check(matches(withText(testUser.email)))
}
}
6. 性能优化考量
6.1 数据流优化
// 使用Flow进行响应式编程
class UserViewModel : ViewModel() {
val user: Flow<User> = repository.getUserFlow()
.map { it.toUiModel() }
.onStart { emit(loadingState) }
.catch { emit(errorState(it)) }
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = UserState.Loading
)
}
6.2 内存管理
- 使用
ViewModelScope
避免内存泄漏 - 适时取消协程(
viewModelScope.launch
自动管理) - 使用
SavedStateHandle
保存关键状态
7. 架构选择指南
MVC
适用场景:简单页面、快速原型
- ✅ 结构简单
- ❌ 难以测试、Activity臃肿
MVP
适用场景:需要高测试覆盖率的应用
- ✅ 视图与逻辑完全解耦
- ❌ 接口数量多、维护成本高
MVVM
适用场景:大多数业务场景(Google推荐)
- ✅ 数据绑定减少模板代码
- ✅ 生命周期感知安全
- ❌ 双向绑定调试复杂
MVI
适用场景:复杂状态管理、需要可预测数据流
- ✅ 状态不可变性
- ✅ 单向数据流易于调试
- ❌ 样板代码较多
8. 未来趋势
- 多平台共享:KMM(Kotlin Multiplatform)架构
- 声明式UI:Jetpack Compose与架构组件深度整合
- 响应式增强:Flow与Channel的更广泛应用
总结
Android数据架构的核心演进体现了关注点分离和可测试性的持续优化。现代架构选择应基于:
- 应用复杂度:简单页面可用MVVM,复杂状态管理推荐MVI
- 团队规范:统一架构模式降低维护成本
- 测试需求:MVP和MVVM更适合单元测试
- 技术债务:逐步重构而非推倒重来
掌握架构模式的核心思想比机械套用更重要,最终目标是构建可维护、可测试、可扩展的Android应用。