提问人:NewPartizal 提问时间:10/27/2023 最后编辑:NewPartizal 更新时间:11/1/2023 访问量:81
如何在 kotlin jetpack compose 中创建单例对象并用于两个屏幕的 UI 和视图模型?
How to create singleton object and using for UI and viewmodel for two screen in kotlin jetpack compose?
问:
我有这样的清单
data class SelectedNtrItem(
val items:ArrayList<NutritionSearchItem> = arrayListOf()
)
我需要在两个可组合的屏幕上使用此列表,因此我需要访问其中的单个示例。我的想法是用 singelton 创建它并在 UI 和 Viewmodel 端使用它,但我无法完全做到这一点。
class SelectedNtrItemManager {
companion object{
private val _selectedNtrItem = MutableStateFlow(SelectedNtrItem())
val selectedNtrItem: StateFlow<SelectedNtrItem> = _selectedNtrItem.asStateFlow()
}
}
这是我创建的 singelton 类。如何在两个可组合屏幕的视图模型和UI端使用它,也就是说,我如何在两个屏幕上的UI端和视图模型端作为单个对象访问此列表,因为我需要相同的列表?
@Composable
fun FirstScreen(
navHostController: NavHostController,
viewModel: FirstScreenViewModel = hiltViewModel()
) {
...
@HiltViewModel
class FirstScreenViewModel @Inject constructor(
.... ) : ViewModel() { ....
@Composable
fun SecondScreen(
navHostController: NavHostController,
viewModel: SecondScreenViewModel = hiltViewModel()
) {
...
@HiltViewModel
class SecondScreenViewModel @Inject constructor(
.... ) : ViewModel() { ....
解决
我解决了下面的问题:
object SelectedNtrItemManager {
var selectedItems = SnapshotStateList<NutritionSearchItem>()
fun addItem(item: NutritionSearchItem) {
selectedItems.add(item)
}
fun removeItem(item: NutritionSearchItem) {
selectedItems.remove(item)
}
}
FirstScreen 虚拟机:
val selectedItems: SnapshotStateList<NutritionSearchItem>
get() = SelectedNtrItemManager.selectedItems
fun addSelectedNutritionItem(
ntrItem: NutritionSearchItem
) {
if (selectedItems.contains(ntrItem)) {
SelectedNtrItemManager.removeItem(ntrItem)
} else {
SelectedNtrItemManager.addItem(ntrItem)
}
}
SecondScreen 虚拟机
class SecondScreenVM : ViewModel() {
val list: SnapshotStateList<NutritionSearchItem>
get() = SelectedNtrItemManager.selectedItems
fun deleteItemFromList(item: NutritionSearchItem) {
SelectedNtrItemManager.removeItem(item)
}
}
SecondScreen 用户界面:
val list = viewModel.list
LazyColumn(modifier = Modifier.padding(15.dp)) {
items(list) { item ->....
为了检测我所做的更改,我使用了 SnapshotStateList。SnapshotStateList 检测何时发生更改并通知听众,我像上面一样更新了我的 SelectedNtrItemManager,它运行良好。
答:
1赞
Faruk Karaca
10/28/2023
#1
您需要按如下方式创建 ViewModel,并将其作为参数传递到相关屏幕。
private val sharedViewModel by viewModels<SharedViewModel>()
@Composable
fun FirstScreen(
viewModel: SharedViewModel
) {
}
@Composable
fun SecondScreen(
viewModel: SharedViewModel
) {
}
1赞
froots
10/30/2023
#2
我会将数据对象放入某种 Repository 类中,该类会注入到您的两个 ViewModel 中。在那里,您可以将其收集为流,然后将其收集到可组合项中。
class Repository {
val itemListFlow = MutableSharedFlow<SelectedNtrItem>()
}
class FirstScreenViewModel(repository: Repository): ViewModel() {
val itemListFlow = repository.itemListFlow.stateIn(viewModelScope, SharingStarted.Eagerly, null)
}
@Composable
fun FirstScreen(
navHostController: NavHostController,
viewModel: FirstScreenViewModel = hiltViewModel()
) {
val list by viewModel.itemListFlow.collectAsState()
}
class SecondScreenViewModel(repository: Repository): ViewModel() {
val itemListFlow = repository.itemListFlow.stateIn(viewModelScope, SharingStarted.Eagerly, null)
}
@Composable
fun SecondScreen(
navHostController: NavHostController,
viewModel: FirstScreenViewModel = hiltViewModel()
) {
val list by viewModel.itemListFlow.collectAsState()
}
评论
0赞
NewPartizal
10/31/2023
我怎样才能将其用于第二个屏幕?您可以通过添加第二个屏幕来执行您要做的事情吗?
0赞
froots
10/31/2023
我编辑了我的答案,只是做与你的第一个视图模型和可组合模型完全相同的事情
0赞
NewPartizal
10/31/2023
这是行不通的。
0赞
froots
11/2/2023
我忘记了您需要在 Hilt 中将存储库声明为单例。我不是刀柄专家,但我认为它只是使用@Singleton注释。
评论