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.
相关产品推荐
相关产品推荐

