You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose LazyColumn设备旋转后停止更新问题求助

问题解决与代码优化

核心问题原因

  • ViewModel未被正确托管:MainActivity中手动new MainActivityViewModel(this),设备旋转时Activity重建会创建全新ViewModel实例,旧实例的StateFlow订阅中断,新实例无法持续接收数据库更新。
  • 内存泄漏风险:ViewModel构造函数接收Activity参数,其生命周期长于Activity,会导致内存泄漏。
  • Repository初始化不规范:直接在ViewModel中实例化Repository并传递Activity上下文,既不符合依赖设计原则,也存在泄漏风险。

问题修复步骤

1. 正确创建ViewModel实例

在Compose中使用viewModel()函数获取ViewModel,该函数会自动托管ViewModel生命周期,设备旋转时保留同一实例:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            // 改用viewModel()获取托管实例,而非手动new
            val viewModel: MainActivityViewModel = viewModel()
            val orders by viewModel.mainUiState.collectAsState()

            OrdersTheme {
                Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
                    Column {
                        // 移除不必要的Activity参数传递
                        OrderList(orders = orders)
                    }
                }
            }
        }
    }
}

2. 修改ViewModel构造函数,避免持有Activity引用

改用Application上下文初始化Repository,切断ViewModel与Activity的直接关联:

class MainActivityViewModel(application: Application) : ViewModel() {
    private val repository = OrderRepository(application)

    val mainUiState: StateFlow<MainActivityUiState> = repository.getOrders()
        .map { MainActivityUiState(it) }
        .stateIn(
            scope = viewModelScope,
            // 若需后台持续同步数据,可改用SharingStarted.Eagerly;保留WhileSubscribed则需确保UI始终订阅
            started = SharingStarted.Eagerly,
            initialValue = MainActivityUiState()
        )

    data class MainActivityUiState(val itemList: List<Order> = listOf())
}

3. 清理Composable函数的冗余参数

移除不必要的Activity参数传递,简化Composable依赖:

@Composable
fun OrderList(modifier: Modifier = Modifier, orders: MainActivityViewModel.MainActivityUiState) {
    Column(modifier = modifier) {
        LazyColumn(contentPadding = PaddingValues(50.dp)) {
            itemsIndexed(orders.itemList) { index, item ->
                OrderItem(order = item)
            }
        }
    }
}

代码优化方向

1. 引入依赖注入(Hilt)优化组件管理

手动实例化Repository和ViewModel不利于测试与维护,建议用Hilt实现依赖注入:

  • 为OrderRepository添加@Inject构造函数,使用Application上下文:
class OrderRepository @Inject constructor(application: Application) {
    private val db: OrderDatabase = Room.databaseBuilder(
        application.applicationContext,
        OrderDatabase::class.java, "orders"
    ).fallbackToDestructiveMigration().build()

    // 私有化Dao,封装数据库操作细节
    private val orderDao: OrderDao = db.orderDao()

    fun getOrders(): Flow<List<Order>> {
        return orderDao.loadAllOrders()
    }

    // 封装增删改操作,对外暴露业务方法而非Dao
    suspend fun addOrder(order: Order) {
        orderDao.insertOrder(order)
    }
}
  • 为ViewModel添加@HiltViewModel注解,通过构造函数注入Repository:
@HiltViewModel
class MainActivityViewModel @Inject constructor(
    private val repository: OrderRepository
) : ViewModel() {
    val mainUiState: StateFlow<MainActivityUiState> = repository.getOrders()
        .map { MainActivityUiState(it) }
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5_000L),
            initialValue = MainActivityUiState()
        )

    data class MainActivityUiState(val itemList: List<Order> = listOf())
}
  • 在MainActivity添加@AndroidEntryPoint注解,启用Hilt:
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    // 其余代码不变
}

2. 统一数据类命名

代码中存在Order与Ordine的拼写不一致问题,需统一命名避免编译错误。

内容的提问来源于stack exchange,提问作者A.M.P.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 15:39:55