Kotlin MVVM架构最佳实践指南

771 阅读2分钟

在Kotlin中实现MVVM架构时,ViewModel和LiveData是两个核心组件,它们能有效实现关注点分离和数据驱动UI的特性。以下是详细的实现指南:


一、MVVM组件职责划分

  1. Model层

    • 数据模型(Data Classes)
    • 数据源(Repository):管理本地/远程数据
    • 业务逻辑处理
  2. ViewModel层

    • 持有和管理与UI相关的数据
    • 通过LiveData暴露数据状态
    • 处理View层的事件响应
    • 不持有View引用
  3. View层(Activity/Fragment)

    • 观察ViewModel的LiveData
    • 处理UI渲染和用户交互
    • 最小化业务逻辑

二、环境配置(build.gradle)

// AndroidX依赖
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'
implementation 'androidx.activity:activity-ktx:1.6.1'  // 简化ViewModel获取

三、核心实现步骤

1. 数据模型与Repository

// 数据模型
data class User(val id: Int, val name: String)

// Repository示例
class UserRepository {
    private val fakeRemoteData = listOf(User(1, "Alice"), User(2, "Bob"))

    suspend fun loadUsers(): List<User> {
        // 模拟网络请求
        delay(1000)
        return fakeRemoteData
    }
}

2. ViewModel实现

class UserViewModel(
    private val repository: UserRepository
) : ViewModel() {

    private val _users = MutableLiveData<List<User>>()
    val users: LiveData<List<User>> = _users

    private val _loadingState = MutableLiveData<Boolean>()
    val loadingState: LiveData<Boolean> = _loadingState

    fun fetchUsers() {
        viewModelScope.launch {
            _loadingState.value = true
            try {
                val result = repository.loadUsers()
                _users.value = result
            } catch (e: Exception) {
                // 错误处理(可通过LiveData传递错误状态)
            } finally {
                _loadingState.value = false
            }
        }
    }
}

3. View层实现(Activity/Fragment)

class MainActivity : AppCompatActivity() {
    private val viewModel: UserViewModel by viewModels {
        UserViewModelFactory(UserRepository())
    }

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

        setupObservers()
        viewModel.fetchUsers()
    }

    private fun setupObservers() {
        viewModel.users.observe(this) { users ->
            // 更新RecyclerView
            adapter.submitList(users)
        }

        viewModel.loadingState.observe(this) { isLoading ->
            progressBar.visibility = if (isLoading) View.VISIBLE else View.GONE
        }
    }
}

// ViewModel工厂(带参数构造时使用)
class UserViewModelFactory(private val repository: UserRepository) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return UserViewModel(repository) as T
    }
}

四、高级实践技巧

1. 使用密封类封装状态

sealed class Resource<T>(
    val data: T? = null,
    val error: Throwable? = null
) {
    class Success<T>(data: T) : Resource<T>(data)
    class Loading<T>(data: T? = null) : Resource<T>(data)
    class Error<T>(throwable: Throwable, data: T? = null) : Resource<T>(data, throwable)
}

// ViewModel中使用:
private val _state = MutableLiveData<Resource<List<User>>>()
val state: LiveData<Resource<List<User>>> = _state

2. 数据绑定集成

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

    <TextView
        android:text="@{viewModel.user.name}"
        android:visibility="@{viewModel.loading ? View.GONE : View.VISIBLE}" />
</layout>

3. 事件处理(避免重复触发)

class SingleLiveEvent<T> : MutableLiveData<T>() {
    private val pending = AtomicBoolean(false)

    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
        super.observe(owner) { t ->
            if (pending.compareAndSet(true, false)) {
                observer.onChanged(t)
            }
        }
    }

    override fun setValue(value: T) {
        pending.set(true)
        super.setValue(value)
    }
}

五、最佳实践原则

  1. 单向数据流: View → ViewModel → Model → ViewModel → View

  2. 生命周期感知

    • 使用viewLifecycleOwner(在Fragment中)
    • 避免在非活跃状态更新UI
  3. 测试策略

    • ViewModel:使用JUnit测试业务逻辑
    • LiveData:利用observeForTesting
    • Repository:Mock数据源测试
  4. 内存管理

    • 避免在ViewModel中持有Context
    • 使用WeakReference处理必要的外部依赖

六、MVVM优势总结

特性优势说明
关注点分离UI逻辑与业务逻辑解耦
生命周期感知自动管理资源释放,避免内存泄漏
数据持久化ViewModel在配置更改后保持数据
可测试性各组件可独立测试
响应式编程LiveData自动通知UI更新

通过合理使用ViewModel和LiveData,可以构建出健壮、可维护且符合现代Android开发规范的应用程序架构。