Android中高级面试(二):架构组件与协程实战精要

85 阅读3分钟

原文: xuanhu.info/projects/it…

Android中高级面试(二):架构组件与协程实战精要

🔍 一、ViewModel 架构组件深度剖析

1.1 ViewModel 的生命周期管理机制


class UserViewModel : ViewModel() {

private val _userData = MutableLiveData<User>()

val userData: LiveData<User> get() = _userData

  


// 数据加载逻辑封装在ViewModel中

fun loadUser(userId: String) {

viewModelScope.launch {

_userData.value = repository.fetchUser(userId)

}

}

}

  


// Activity/Fragment中的使用

class ProfileActivity : AppCompatActivity() {

private val viewModel by viewModels<UserViewModel>()

  


override fun onCreate(savedInstanceState: Bundle?) {

viewModel.userData.observe(this) { user ->

updateUI(user)

}

}

}

核心机制解析

ViewModel 通过 ViewModelStore 实现与UI控制器的生命周期解耦,其存活周期从首次获取到Activity finish或Fragment detach。当设备旋转时,Activity重建但ViewModel实例保持不变,避免数据重复加载。

1.2 SavedStateHandle 的数据持久化


class SearchViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {

val query: MutableLiveData<String> = savedStateHandle.getLiveData("query_key")

  


fun setQuery(query: String) {

savedStateHandle["query_key"] = query

}

}

  


// 获取实例时注入SavedStateHandle

val viewModel: SearchViewModel by viewModels {

SavedStateViewModelFactory(application, this)

}

应用场景

当进程因系统资源回收被杀时,SavedStateHandle 可自动恢复数据。其内部采用Bundle存储机制,支持基本数据类型及Parcelable对象。

🌊 二、LiveData 高级应用与陷阱规避

2.1 Transformations 操作符实战


val userIdLiveData = MutableLiveData<String>()

val userLiveData: LiveData<User> = Transformations.switchMap(userIdLiveData) { id ->

repository.getUserById(id)

}

  


// 复合数据转换示例

val userProfile = Transformations.map(userLiveData) { user ->

"${user.name} | ${user.email}"

}

2.2 避免LiveData的常见陷阱

内存泄漏防范


// 错误示例:在Activity中使用匿名Observer

viewModel.data.observe(this) { data ->

updateView(data)

// 当Activity销毁时,此匿名Observer无法自动移除

}

  


// 正确方案:使用LifecycleOwner

class ProfileFragment : Fragment() {

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

viewModel.data.observe(viewLifecycleOwner) { data ->

updateViews(data)

}

}

}

🚀 三、Kotlin协程在Android中的工程实践

3.1 结构化并发模型


class OrderViewModel : ViewModel() {

private val _orderStatus = MutableLiveData<OrderStatus>()

val orderStatus: LiveData<OrderStatus> get() = _orderStatus

  


fun fetchOrderDetails(orderId: String) {

viewModelScope.launch(Dispatchers.IO) {

try {

val order = repository.getOrder(orderId)

withContext(Dispatchers.Main) {

_orderStatus.value = OrderStatus.Success(order)

}

} catch (e: Exception) {

_orderStatus.value = OrderStatus.Error(e)

}

}

}

}

并发控制技巧


// 并行请求优化

suspend fun fetchDashboardData() = coroutineScope {

val userDeferred = async { getUserData() }

val notificationsDeferred = async { getNotifications() }

val user = userDeferred.await()

val notifications = notificationsDeferred.await()

DashboardData(user, notifications)

}

3.2 协程与Room数据库的深度集成


@Dao

interface UserDao {

@Query("SELECT * FROM users")

fun getAllUsers(): Flow<List<User>> // 使用Flow实现实时数据库监听

  


@Insert

suspend fun insertUser(user: User) // 挂起函数保证线程安全

}

  


// ViewModel中使用

viewModelScope.launch {

userDao.getAllUsers().collect { users ->

_userList.value = users

}

}

⚡ 四、性能优化与架构设计进阶

4.1 响应式UI架构设计


graph TD

A[Activity/Fragment] -->|观察| B(ViewModel)

B -->|调用| C(Repository)

C -->|请求| D[Remote DataSource]

C -->|查询| E[Local DataSource]

D -->|网络数据| C

E -->|数据库数据| C

4.2 内存泄漏检测与防范


// 使用Android Profiler检测步骤:

// 1. 执行可能泄漏的操作(如旋转设备)

// 2. 触发GC

// 3. 检查Activity/Fragment实例是否仍被持有

  


// 使用LeakCanary自动检测

dependencies {

debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'

}

💡 五、高频面试题精析

5.1 ViewModel vs onSaveInstanceState

特性ViewModelonSaveInstanceState
数据存活范围直到Activity销毁进程被杀死后重建
数据类型限制支持复杂对象仅支持基本类型和Parcelable
适用场景屏幕旋转保持数据进程回收后恢复数据

5.2 LiveData与StateFlow对比


// LiveData示例

viewModel.data.observe(viewLifecycleOwner) { data ->

updateUI(data)

}

  


// StateFlow示例

viewModel.uiState.collectLatest { state ->

when (state) {

is UiState.Loading -> showProgress()

is UiState.Success -> showData(state.data)

is UiState.Error -> showError(state.exception)

}

}

总结

📚 核心要点回顾

  1. ViewModel架构优势
  • 生命周期感知的数据持有者

  • 配合SavedStateHandle实现进程回收恢复

  • 通过ViewModelProvider.Factory实现依赖注入

  1. LiveData高级用法
  • Transformations实现数据流转换

  • 配合LifecycleOwner避免内存泄漏

  • 与DataBinding的双向绑定集成

  1. 协程最佳实践
  • 结构化并发保障任务可管理

  • viewModelScope自动取消机制

  • Flow实现数据库实时监听

  1. 性能优化方向
  • 使用Profiler检测内存泄漏

  • 避免在ViewModel持有Context

  • 合理使用Dispatchers控制线程切换

面试实战建议:在解释技术原理时,务必结合具体业务场景。例如当被问到“如何保证数据在屏幕旋转时不丢失”,可回答:“采用ViewModel保存业务数据,同时使用SavedStateHandle处理进程回收场景,具体实现如代码示例中所示...”

技术演进趋势

Android架构领域的新动向:

  1. Compose与ViewModel深度整合:在Compose函数中通过viewModel()直接获取实例

  2. Coroutine Worker:将协程与WorkManager结合实现后台任务

  3. DataStore全面替代SharedPreferences:提供异步API与Flow支持

原文: xuanhu.info/projects/it…