xDocxDoc
AI
前端
后端
iOS
Android
Flutter
AI
前端
后端
iOS
Android
Flutter
  • 你真的了解 Android ViewModel 么?:试试这6个问题

你真的了解 Android ViewModel 么?:试试这6个问题

作为Android开发者,ViewModel是我们日常开发中不可或缺的架构组件。但你真的掌握它的所有精髓了吗?本文将通过6个实战场景,深度剖析ViewModel的关键知识点,每个场景都配有完整的代码示例和架构思考,帮助你在实际项目中游刃有余地使用ViewModel。

🎯 场景一:配置更改时数据如何保持?——ViewModel的生命周期管理

问题背景

在传统Android开发中,当屏幕旋转、语言切换等配置更改发生时,Activity会被销毁重建,导致临时数据丢失。开发者通常使用onSaveInstanceState()来保存简单数据,但这种方法对于复杂对象(如用户列表、网络请求结果)存在局限性。

ViewModel的解决方案

ViewModel的核心设计目标就是以生命周期感知的方式存储和管理界面相关的数据。它的生命周期比关联的Activity或Fragment更长,在配置更改时不会被销毁,只有当其所有者永久销毁时才会清理。

代码实战:计数器ViewModel

/**
 * 计数器ViewModel示例
 * 演示如何在配置更改时保持数据状态
 */
class CounterViewModel : ViewModel() {
    // 使用MutableLiveData存储计数状态,便于观察变化
    private val _count = MutableLiveData(0)
    
    // 对外暴露不可变的LiveData,保证数据封装性
    val count: LiveData<Int> get() = _count
    
    /**
     * 增加计数的方法
     */
    fun increment() {
        _count.value = _count.value?.plus(1)
    }
    
    /**
     * 重写onCleared方法,在ViewModel销毁时进行资源清理
     */
    override fun onCleared() {
        super.onCleared()
        // 在这里释放资源,如取消网络请求
    }
}

/**
 * 使用ViewModel的Activity示例
 */
class MainActivity : AppCompatActivity() {
    // 使用委托模式简化ViewModel获取
    private val viewModel: CounterViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        // 观察count数据的变化,自动更新UI
        viewModel.count.observe(this) { count ->
            // 当数据变化时,TextView自动更新
            tvCounter.text = "Count: $count"
        }
        
        // 按钮点击时增加计数
        btnIncrement.setOnClickListener { 
            viewModel.increment() 
        }
    }
}

底层原理剖析

ViewModel的生命周期管理依赖于ViewModelStore机制。当配置更改时,Activity的ViewModelStore会被保留,新的Activity实例会复用原有的ViewModel。

// 简化的ViewModelStore工作原理
public class ComponentActivity {
    public ViewModelStore getViewModelStore() {
        if (mViewModelStore == null) {
            // 从上次配置变更恢复ViewModelStore
            NonConfigurationInstances nc = getLastNonConfigurationInstance();
            if (nc != null) {
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }
}

实战技巧

  • 数据持久化选择:简单数据使用onSaveInstanceState(),复杂数据使用ViewModel
  • 内存管理:ViewModel中避免持有View或Activity引用,防止内存泄漏
  • 资源清理:在onCleared()方法中及时释放资源

🔄 场景二:多Fragment如何共享数据?——SharedViewModel实战

问题背景

在单Activity多Fragment的架构中,经常需要在不同Fragment之间共享数据。传统的解决方案是通过Activity中转或者使用接口回调,但这些方法会导致代码耦合度高、维护困难。

SharedViewModel解决方案

SharedViewModel通过将ViewModel的作用域限定到Activity级别,使得同一Activity下的所有Fragment可以共享同一个ViewModel实例,实现高效的数据共享和通信。

代码实战:主从布局数据共享

/**
 * 共享ViewModel示例:用于主Fragment和详情Fragment之间的数据通信
 */
class SharedViewModel : ViewModel() {
    // 当前选中的项目,使用LiveData便于观察变化
    private val _selectedItem = MutableLiveData<Item>()
    val selectedItem: LiveData<Item> get() = _selectedItem
    
    /**
     * 选择项目的方法
     * @param item 被选中的项目
     */
    fun selectItem(item: Item) {
        _selectedItem.value = item
    }
}

/**
 * 主Fragment:显示项目列表
 */
class MasterFragment : Fragment() {
    // 使用activityViewModels委托获取Activity作用域的ViewModel
    private val sharedViewModel: SharedViewModel by activityViewModels()
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        // 设置列表点击监听器
        itemList.setOnItemClickListener { item ->
            // 选择项目时更新SharedViewModel
            sharedViewModel.selectItem(item)
            
            // 导航到详情Fragment
            findNavController().navigate(R.id.to_detail_fragment)
        }
    }
}

/**
 * 详情Fragment:显示选中项目的详情
 */
class DetailFragment : Fragment() {
    // 获取与MasterFragment相同的ViewModel实例
    private val sharedViewModel: SharedViewModel by activityViewModels()
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        // 观察选中项目的变化,自动更新UI
        sharedViewModel.selectedItem.observe(viewLifecycleOwner) { item ->
            // 当项目被选择时,更新详情显示
            tvItemName.text = item.name
            tvItemDescription.text = item.description
        }
    }
}

作用域控制进阶

在复杂的Fragment嵌套场景中,需要精确控制ViewModel的作用域:

/**
 * 嵌套Fragment中的ViewModel作用域控制示例
 */
class ParentFragment : Fragment() {
    // 父Fragment的私有ViewModel
    private val parentViewModel: ParentViewModel by viewModels()
}

class ChildFragment : Fragment() {
    // 方案1:获取父Fragment的ViewModel(局部共享)
    private val parentViewModel: ParentViewModel by viewModels({ requireParentFragment() })
    
    // 方案2:获取Activity级别的ViewModel(全局共享)
    private val globalViewModel: GlobalViewModel by activityViewModels()
    
    // 方案3:混合使用不同作用域的ViewModel
    private val mixedViewModel: MixedViewModel by viewModels(
        { requireParentFragment() }, 
        factoryProducer = { defaultViewModelProviderFactory }
    )
}

架构设计考量

  • 作用域选择:根据数据共享范围选择合适的作用域,避免过度共享
  • 生命周期安全:使用viewLifecycleOwner观察LiveData,避免Fragment视图销毁后的UI更新
  • 模块化设计:通过父Fragment ViewModel实现模块内数据隔离

📡 场景三:如何优雅处理数据更新?——ViewModel与LiveData的协同

问题背景

在MVVM架构中,View(Activity/Fragment)需要响应Model的数据变化。传统方案使用回调接口或EventBus,但这些方法存在生命周期管理复杂、代码耦合度高等问题。

LiveData协同解决方案

LiveData是一个生命周期感知的数据持有类,与ViewModel结合可以实现安全、高效的数据观察和UI更新。

代码实战:网络数据加载

/**
 * 用户数据ViewModel,演示与LiveData的协同使用
 */
class UserViewModel(private val userRepository: UserRepository) : ViewModel() {
    // 加载状态:用于显示进度条等UI反馈
    private val _loadingState = MutableLiveData<Boolean>()
    val loadingState: LiveData<Boolean> get() = _loadingState
    
    // 用户数据列表
    private val _userList = MutableLiveData<List<User>>()
    val userList: LiveData<List<User>> get() = _userList
    
    // 错误信息
    private val _errorMessage = MutableLiveData<String>()
    val errorMessage: LiveData<String> get() = _errorMessage
    
    /**
     * 加载用户数据的方法
     */
    fun loadUsers() {
        _loadingState.value = true
        
        // 使用viewModelScope管理协程生命周期
        viewModelScope.launch {
            try {
                val users = userRepository.getUsers()
                _userList.value = users
                _errorMessage.value = ""
            } catch (e: Exception) {
                _errorMessage.value = "加载失败: ${e.message}"
            } finally {
                _loadingState.value = false
            }
        }
    }
}

/**
 * 使用ViewModel的Activity示例
 */
class UserActivity : AppCompatActivity() {
    private val viewModel: UserViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_user)
        
        // 观察加载状态,显示/隐藏进度条
        viewModel.loadingState.observe(this) { isLoading ->
            progressBar.visibility = if (isLoading) View.VISIBLE else View.GONE
        }
        
        // 观察用户数据变化,更新列表
        viewModel.userList.observe(this) { users ->
            userAdapter.submitList(users)
        }
        
        // 观察错误信息,显示Toast等提示
        viewModel.errorMessage.observe(this) { error ->
            if (error.isNotEmpty()) {
                Toast.makeText(this, error, Toast.LENGTH_SHORT).show()
            }
        }
        
        // 初始加载数据
        viewModel.loadUsers()
    }
}

数据绑定集成

ViewModel还可以与Data Binding结合,进一步简化UI更新代码:

<!-- layout_user_activity.xml -->
<layout>
    <data>
        <variable
            name="viewModel"
            type="com.example.UserViewModel" />
    </data>
    
    <LinearLayout>
        <ProgressBar
            android:visibility="@{viewModel.loadingState ? View.VISIBLE : View.GONE}" />
            
        <TextView
            android:text="@{viewModel.errorMessage}"
            android:visibility="@{viewModel.errorMessage.isEmpty() ? View.GONE : View.VISIBLE}" />
            
        <androidx.recyclerview.widget.RecyclerView
            app:listData="@{viewModel.userList}"
            app:adapter="@{userAdapter}" />
    </LinearLayout>
</layout>

高级模式:StateFlow替代LiveData

对于更复杂的状态管理,可以考虑使用StateFlow:

class UserViewModel : ViewModel() {
    // 使用StateFlow管理复合状态
    private val _uiState = MutableStateFlow<UserUiState>(UserUiState.Loading)
    val uiState: StateFlow<UserUiState> = _uiState.asStateFlow()
    
    fun loadUsers() {
        viewModelScope.launch {
            _uiState.value = UserUiState.Loading
            try {
                val users = userRepository.getUsers()
                _uiState.value = UserUiState.Success(users)
            } catch (e: Exception) {
                _uiState.value = UserUiState.Error(e.message ?: "Unknown error")
            }
        }
    }
}

// 密封类定义所有可能的UI状态
sealed class UserUiState {
    object Loading : UserUiState()
    data class Success(val users: List<User>) : UserUiState()
    data class Error(val message: String) : UserUiState()
}

🏗️ 场景四:如何初始化带参数的ViewModel?——ViewModelProvider.Factory模式

问题背景

ViewModel的默认构造函数是无参的,但在实际项目中,我们经常需要向ViewModel传递参数(如用户ID、Repository实例等)。直接在新Activity中创建ViewModel实例会导致配置更改时无法保持数据一致性。

Factory模式解决方案

使用ViewModelProvider.Factory接口可以自定义ViewModel的创建过程,支持参数传递和依赖注入。

代码实战:依赖注入ViewModel

/**
 * 需要参数的ViewModel示例
 * @param userId 用户ID,用于数据加载
 * @param userRepository 数据仓库,用于业务逻辑处理
 */
class UserViewModel(
    private val userId: String,
    private val userRepository: UserRepository
) : ViewModel() {
    private val _userData = MutableLiveData<User>()
    val userData: LiveData<User> get() = _userData
    
    init {
        loadUserData()
    }
    
    private fun loadUserData() {
        viewModelScope.launch {
            val user = userRepository.getUserById(userId)
            _userData.value = user
        }
    }
}

/**
 * 自定义ViewModelFactory,负责创建带参数的ViewModel
 * @param userId 要传递的用户ID
 * @param repository 要注入的Repository实例
 */
class UserViewModelFactory(
    private val userId: String,
    private val repository: UserRepository
) : ViewModelProvider.Factory {
    
    /**
     * 创建ViewModel实例的核心方法
     * @param modelClass 要创建的ViewModel类
     * @return 创建的ViewModel实例
     */
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (!modelClass.isAssignableFrom(UserViewModel::class.java)) {
            throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.simpleName}")
        }
        return UserViewModel(userId, repository) as T
    }
}

/**
 * 在Activity中使用自定义Factory创建ViewModel
 */
class UserProfileActivity : AppCompatActivity() {
    private lateinit var viewModel: UserViewModel
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_user_profile)
        
        // 获取参数(例如从Intent中)
        val userId = intent.getStringExtra("USER_ID") ?: ""
        
        // 创建Repository实例(实际项目中可能通过DI框架注入)
        val userRepository = provideUserRepository()
        
        // 创建自定义Factory
        val factory = UserViewModelFactory(userId, userRepository)
        
        // 通过ViewModelProvider和Factory创建ViewModel
        viewModel = ViewModelProvider(this, factory).get(UserViewModel::class.java)
        
        // 观察数据变化
        viewModel.userData.observe(this) { user ->
            tvUserName.text = user.name
            tvUserEmail.text = user.email
        }
    }
    
    private fun provideUserRepository(): UserRepository {
        // 实际项目中可能通过Dagger、Koin等DI框架提供
        return UserRepositoryImpl()
    }
}

依赖注入框架集成

结合Koin依赖注入框架的简化方案:

// 使用Koin进行依赖注入
val userModule = module {
    // 定义ViewModel,自动注入参数
    viewModel { (userId: String) ->
        UserViewModel(
            userId = userId,
            userRepository = get()
        )
    }
}

// 在Activity中直接获取ViewModel
class UserProfileActivity : AppCompatActivity() {
    private val viewModel: UserViewModel by viewModel { 
        parametersOf(intent.getStringExtra("USER_ID") ?: "") 
    }
    
    // ... 其他代码
}

高级技巧:抽象Base Factory

对于大型项目,可以创建基础的Factory类:

/**
 * 基础的ViewModelFactory,支持多种创建方式
 */
abstract class BaseViewModelFactory : ViewModelProvider.Factory {
    
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return createViewModel(modelClass) as? T
            ?: throw IllegalArgumentException("Cannot create instance of ${modelClass.simpleName}")
    }
    
    abstract fun <T : ViewModel> createViewModel(modelClass: Class<T>): T
}

/**
 * 具体的UserViewModelFactory实现
 */
class UserViewModelFactory(
    private val userId: String,
    private val repository: UserRepository
) : BaseViewModelFactory() {
    
    override fun <T : ViewModel> createViewModel(modelClass: Class<T>): T {
        return when {
            modelClass.isAssignableFrom(UserViewModel::class.java) -> {
                UserViewModel(userId, repository) as T
            }
            else -> throw IllegalArgumentException("Unknown ViewModel class")
        }
    }
}

🌐 场景五:何时需要访问上下文?——AndroidViewModel的特殊场景

问题背景

普通ViewModel禁止持有Context引用以避免内存泄漏,但有些场景确实需要访问系统服务(如位置服务、SharedPreferences等)。这时就需要使用AndroidViewModel。

AndroidViewModel解决方案

AndroidViewModel是ViewModel的子类,通过构造函数传入Application上下文,这个上下文是全局单例,不会导致内存泄漏。

代码实战:位置服务ViewModel

/**
 * AndroidViewModel示例:需要访问系统服务的场景
 * @param application Application上下文,用于获取系统服务
 */
class LocationViewModel(application: Application) : AndroidViewModel(application) {
    
    // 通过Application上下文获取位置服务
    private val locationManager = application.getSystemService(Context.LOCATION_SERVICE) as LocationManager
    
    // 当前位置信息
    private val _currentLocation = MutableLiveData<Location>()
    val currentLocation: LiveData<Location> get() = _currentLocation
    
    // 位置监听器
    private val locationListener = object : LocationListener {
        override fun onLocationChanged(location: Location) {
            _currentLocation.value = location
        }
    }
    
    /**
     * 开始监听位置变化
     */
    fun startLocationUpdates() {
        try {
            locationManager.requestLocationUpdates(
                LocationManager.GPS_PROVIDER,
                1000L,  // 更新间隔:1秒
                1f,     // 最小距离:1米
                locationListener
            )
        } catch (e: SecurityException) {
            Log.e("LocationViewModel", "位置权限被拒绝", e)
        }
    }
    
    /**
     * 停止监听位置变化
     */
    fun stopLocationUpdates() {
        locationManager.removeUpdates(locationListener)
    }
    
    /**
     * 重写onCleared方法,确保资源被正确释放
     */
    override fun onCleared() {
        super.onCleared()
        stopLocationUpdates()
    }
}

/**
 * 使用AndroidViewModel的Activity示例
 */
class LocationActivity : AppCompatActivity() {
    private val locationViewModel: LocationViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_location)
        
        // 观察位置变化
        locationViewModel.currentLocation.observe(this) { location ->
            tvLatitude.text = "纬度: ${location.latitude}"
            tvLongitude.text = "经度: ${location.longitude}"
        }
        
        btnStartLocation.setOnClickListener {
            locationViewModel.startLocationUpdates()
        }
        
        btnStopLocation.setOnClickListener {
            locationViewModel.stopLocationUpdates()
        }
    }
    
    override fun onPause() {
        super.onPause()
        // 根据业务需求决定是否在后台继续更新位置
        locationViewModel.stopLocationUpdates()
    }
}

普通ViewModel vs AndroidViewModel对比

普通ViewModel
class NormalViewModel : ViewModel() {
    // 优点:轻量级,无内存泄漏风险
    // 缺点:无法直接访问系统服务
    
    fun processData(data: String) {
        // 纯数据处理逻辑,不需要上下文
    }
}
AndroidViewModel
class SpecializedViewModel(application: Application) : AndroidViewModel(application) {
    // 优点:可以安全访问系统服务
    // 缺点:稍重,需要传递Application参数
    
    private val sharedPrefs = application.getSharedPreferences("prefs", Context.MODE_PRIVATE)
    
    fun savePreference(key: String, value: String) {
        sharedPrefs.edit().putString(key, value).apply()
    }
}

其他需要AndroidViewModel的场景

  1. SharedPreferences操作
class PreferencesViewModel(application: Application) : AndroidViewModel(application) {
    private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(application)
    
    fun getThemePreference(): String {
        return sharedPreferences.getString("theme", "light") ?: "light"
    }
}
  1. 系统资源访问
class ResourceViewModel(application: Application) : AndroidViewModel(application) {
    fun getStringResource(@StringRes resId: Int): String {
        return application.getString(resId)
    }
    
    fun getColorResource(@ColorRes resId: Int): Int {
        return ContextCompat.getColor(application, resId)
    }
}
  1. 数据库初始化
class DatabaseViewModel(application: Application) : AndroidViewModel(application) {
    private val database: AppDatabase by lazy {
        Room.databaseBuilder(
            application,
            AppDatabase::class.java, "app-database"
        ).build()
    }
    
    // ... 数据库操作方法
}

🚀 场景六:如何避免常见陷阱?——ViewModel最佳实践大全

问题背景

虽然ViewModel强大,但错误的使用方式会导致内存泄漏、代码臃肿、测试困难等问题。掌握最佳实践是发挥ViewModel威力的关键。

最佳实践全解析

1. 职责单一原则

每个ViewModel应该只负责一个屏幕或功能模块的数据管理。

// ✅ 正确的做法:职责单一
class UserListViewModel : ViewModel() {
    // 只负责用户列表相关逻辑
    fun loadUsers() { /* ... */ }
    fun searchUsers(query: String) { /* ... */ }
}

class UserDetailViewModel : ViewModel() {
    // 只负责用户详情相关逻辑
    fun loadUserDetail(userId: String) { /* ... */ }
    fun updateUser(user: User) { /* ... */ }
}

// ❌ 错误的做法:职责过重
class GodViewModel : ViewModel() {
    // 同时处理用户、订单、消息等各种逻辑
    fun loadUsers() { /* ... */ }
    fun loadOrders() { /* ... */ }
    fun loadMessages() { /* ... */ }
}

2. 避免内存泄漏

ViewModel中绝对不能持有Activity、Fragment或View的引用。

// ✅ 正确的做法:使用LiveData通信
class SafeViewModel : ViewModel() {
    private val _navigationCommand = MutableLiveData<Event<String>>()
    val navigationCommand: LiveData<Event<String>> get() = _navigationCommand
    
    fun navigateToDetail() {
        _navigationCommand.value = Event("detail_screen")
    }
}

// ❌ 错误的做法:直接持有Activity引用
class DangerousViewModel : ViewModel() {
    private var activity: MainActivity? = null  // 内存泄漏风险!
    
    fun setActivity(activity: MainActivity) {
        this.activity = activity
    }
    
    fun showToast() {
        activity?.let { 
            Toast.makeText(it, "Hello", Toast.LENGTH_SHORT).show()
        }
    }
}

3. 结合Repository模式

ViewModel应该专注于UI数据逻辑,业务逻辑委托给Repository层。

/**
 * 分层架构示例
 */
class OrderViewModel(
    private val orderRepository: OrderRepository
) : ViewModel() {
    
    private val _orders = MutableLiveData<List<Order>>()
    val orders: LiveData<List<Order>> get() = _orders
    
    private val _loadingState = MutableLiveData<Boolean>()
    val loadingState: LiveData<Boolean> get() = _loadingState
    
    fun loadOrders() {
        _loadingState.value = true
        viewModelScope.launch {
            try {
                // 委托给Repository处理业务逻辑
                val orders = orderRepository.getOrders()
                _orders.value = orders
            } catch (e: Exception) {
                // 处理错误
            } finally {
                _loadingState.value = false
            }
        }
    }
}

/**
 * Repository层处理复杂业务逻辑
 */
class OrderRepository(
    private val localDataSource: OrderLocalDataSource,
    private val remoteDataSource: OrderRemoteDataSource
) {
    suspend fun getOrders(): List<Order> {
        // 复杂的业务逻辑:缓存策略、数据转换等
        return try {
            val remoteOrders = remoteDataSource.getOrders()
            localDataSource.saveOrders(remoteOrders)
            remoteOrders
        } catch (e: Exception) {
            localDataSource.getOrders()  // 降级到本地数据
        }
    }
}

4. 测试友好设计

ViewModel应该易于单元测试,通过依赖注入模拟外部依赖。

class UserViewModelTest {
    
    @Test
    fun `test user data loading`() = runTest {
        // 创建Mock Repository
        val mockRepository = mockk<UserRepository>()
        val testUser = User(id = "1", name = "Test User")
        
        // 设置Mock行为
        coEvery { mockRepository.getUser("1") } returns testUser
        
        // 创建ViewModel并注入Mock依赖
        val viewModel = UserViewModel(mockRepository)
        
        // 执行测试逻辑
        viewModel.loadUser("1")
        
        // 验证结果
        assertThat(viewModel.userData.value).isEqualTo(testUser)
    }
}

/**
 * 可测试的ViewModel设计
 */
class TestableViewModel(
    private val userRepository: UserRepository,
    private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.Main
) : ViewModel() {
    
    // 使用可注入的Dispatcher,便于测试控制
    private val testScope = CoroutineScope(coroutineDispatcher + SupervisorJob())
    
    fun loadUser(userId: String) {
        testScope.launch {
            val user = userRepository.getUser(userId)
            // 更新LiveData
        }
    }
    
    override fun onCleared() {
        super.onCleared()
        testScope.cancel()
    }
}

5. 进程死亡恢复:SavedStateHandle

对于需要在进程死亡后恢复的数据,使用SavedStateHandle。

class SavedStateViewModel(
    private val state: SavedStateHandle
) : ViewModel() {
    
    companion object {
        private const val USER_ID_KEY = "userId"
        private const val SEARCH_QUERY_KEY = "searchQuery"
    }
    
    // 自动保存和恢复的数据
    val userId: LiveData<String> = state.getLiveData(USER_ID_KEY)
    val searchQuery: LiveData<String> = state.getLiveData(SEARCH_QUERY_KEY, "")
    
    fun setUserId(id: String) {
        state.set(USER_ID_KEY, id)
    }
    
    fun setSearchQuery(query: String) {
        state.set(SEARCH_QUERY_KEY, query)
    }
}

性能优化技巧

  1. 数据缓存策略
class SmartViewModel : ViewModel() {
    private var cachedData: List<Data>? = null
    
    fun getData(): LiveData<List<Data>> {
        return if (cachedData != null) {
            // 返回缓存数据
            MutableLiveData(cachedData)
        } else {
            // 从网络或数据库加载
            loadDataFromSource()
        }
    }
}
  1. 懒加载优化
class LazyViewModel : ViewModel() {
    // 使用lazy延迟初始化耗时资源
    private val expensiveResource by lazy {
        // 只在第一次访问时初始化
        initializeExpensiveResource()
    }
    
    fun useResource() {
        // 首次调用时才会初始化
        expensiveResource.doSomething()
    }
}

💎 总结

通过这6个核心场景的深度剖析,我们可以看到ViewModel在Android架构中的关键作用。从基本的生命周期管理到复杂的跨组件通信,ViewModel提供了一套完整的数据管理解决方案。

关键知识点回顾

  1. 生命周期感知:ViewModel在配置更改时保持数据,彻底解决屏幕旋转等场景的数据丢失问题
  2. 数据共享机制:通过作用域控制实现Fragment间的高效数据共享
  3. 响应式编程:与LiveData/StateFlow结合实现声明式UI更新
  4. 依赖注入:通过Factory模式支持参数化初始化
  5. 安全上下文访问:AndroidViewModel在需要系统服务时的安全解决方案
  6. 架构最佳实践:遵循单一职责、避免内存泄漏、支持测试等原则

架构演进思考

随着Android开发的不断发展,ViewModel也在与新技术融合:

  • Jetpack Compose:ViewModel作为状态提升(State Hoisting)的核心
  • KMP(Kotlin Multiplatform):ViewModel的跨平台应用可能性
  • 微服务架构:ViewModel在模块化开发中的角色演变

ViewModel不仅仅是数据存储的工具,更是实现关注点分离、提升代码可维护性的架构核心。掌握这些场景,你就能在复杂的Android项目中游刃有余地构建健壮、可测试的应用程序。