android-livedata 相关问题

Android LiveData保留了该值,并允许它观察更改并尊重应用程序组件的生命周期。

LiveData 在 ViewModel 测试期间返回 NullPointer IsMainThread 错误

尝试观察视图模型中的实时数据时,我的视图模型单元测试一直失败。我从文档中添加了两条规则,即:InstantTaskExecutorRule 和 MainCoroutineRule。我也注射...

回答 1 投票 0

DetailFragment 的 Viewmodel 是否应该在实例之间共享?

我写了一个显示商店列表的主片段,称之为 StoreFeedFragment。如果您单击商店,它会调用 StoreDetailFragment 的 newInstance 以提供所单击商店的详细信息。都

回答 1 投票 0

Jetpack Compose 无法观察 MutableLiveData

查看 viewModel.todoLists.observe(lifecycleOwner){ it?.let { label.value = it.toString() } } 视图模型 val todoLists : MutableLiveData = MutableLiveData() ...

回答 2 投票 0

将项目添加到索引为零的可变列表不会更新 recyclerview

我在一个片段中有一个回收视图,它显示一个可变的任务列表,每个任务都有一个标题和描述,包裹在可变的实时数据中。 私人 val _tasks = MutableLiveData 我在一个片段中有一个 recyclerview,它显示一个可变的任务列表,每个任务都有一个标题和描述,包裹在可变的实时数据中。 private val _tasks = MutableLiveData<MutableList<Task>>() 为了添加这些项目,我实现了一个底部工作表对话框片段,其中包含两个值的文本编辑。 当我在没有指定索引的情况下添加任务项时,recyclerview 会正确更新: _tasks.value!!.add(Task(taskEditText,descriptionEditText)) 但是,当我指定我想要索引 0 处的新任务项并添加多个任务项时,recyclerview 我尝试过的事情: 在适配器内部使用 notifyDataSetChanged 可以正常工作并正确更新 recyclerview,但是我尝试将它添加到底部工作表对话框中的添加任务按钮,但它什么也没做。 我尝试将项目添加到临时列表,然后将其设置为 _tasks.value 但同样的事情发生了,仅在我未指定索引时更新。 这里是相关文件: AddTaskFragment(底部工作表对话框): override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.lifecycleOwner = viewLifecycleOwner // if the textfields are not empty, adds the task and leaves the dialog binding.buttonAdd.setOnClickListener{ if (binding.addTaskEditText.text!!.isNotEmpty() && binding.addDescriptionEditText.text!!.isNotEmpty()) { viewModel.addTask(binding.addTaskEditText.text.toString(), binding.addDescriptionEditText.text.toString()) dismiss() } } } viewmodel 中的 addTask 函数: fun addTask(taskEditText : String, descriptionEditText : String) { _tasks.value!!.add(0,Task(taskEditText,descriptionEditText)) } 适配器: override fun onBindViewHolder(holder: ViewHolder, position: Int) { val task = viewModel.tasks.value!![position] holder.itemTitle.text = task.text holder.itemDescription.text = task.description holder.textViewOptions.setOnClickListener { onMenuClick(position, holder, task) } } 提前致谢,希望专业人士能帮助我 viewModel.tasks.observe(viewLifecycleOwner, Observer { adapter.notifyDataSetChanged() }) 试一试 幕后发生的事情是列表适配器检查旧列表是否与新列表引用相同,在您的情况下是相同的列表,因此它不采取任何操作(查看代码)。但是当 oldList 在引用方面与 newList 不同时,它会更新回收器视图中的项目。如果你想实现它,要么使用不变性作为更新 UI 中项目的模式,要么使用 recyclerview 中可用的其他方法,例如 notifyItemInserted、notifyDataSetChanged 等

回答 2 投票 0

观察函数返回的实时数据

如果我在函数中通过 liveData 返回请求并在活动中观察它以显示响应,我的活动是否总是观察 liveData 或仅在调用函数时观察? 视图模型: 有趣

回答 0 投票 0

可空列表的 MutableLiveData 不通知观察者

给定一个 MutableLiveData val liveData = MutableLiveData?>() 如果我先发送一个有效列表 liveData.postValue(listOf("a", "b", "c")) 然后...

回答 0 投票 0

让每个观察者仅在订阅/观察时收到*新* LiveData

每当您在 LiveData 上调用 .observe() 时,Observer 都会收到该 LiveData 的最后一个值。这在某些情况下可能有用,但在我的情况下没有用。 每当我调用 .observe() 时,我都希望观察者...

回答 4 投票 0

Jetpack 生命周期:Fragment 的视图生命周期永远不会达到 CREATED 状态,永远不会被销毁

问题 我最近注意到一个案例,在 Android 应用程序中,触发了以下异常: java.lang.IllegalArgumentException:无法添加具有不同生命周期的相同观察者 很高兴...

回答 1 投票 0

我无法进入主活动观察功能

我有一个在授予权限时触发的服务类(AccessibilityService)。我检查在 onAccessibilityEvent() 方法中所做的窗口更改并将包名称发送到视图...

回答 0 投票 0

使用 lazycolumn jetpack compose 比使用 recycleview 延迟更多

我刚刚学习了 jetpack compose 并且我从回收切换到 lazycolumn 但是当我这样做时它比回收滞后得多 在向应用程序添加大约 100 个项目后,应用程序滞后,有没有...

回答 0 投票 0

我的实时数据正在更新,但不会触发 android kotlin 中的观察者

我有一个 livedata 变量,我一直在从我的主要活动中监听它,以了解在 UI 线程中执行某些操作的可能更改,但不幸的是它没有被触发。请注意

回答 0 投票 0

在 Android Kotlin Room 中从数据库获取数据时出现问题

我是移动开发的新手。我正在尝试从片段中的 Room 数据库获取 LiveData,我没有收到任何错误,但 Observer 回调为空。我的数据库包含数据,我可以访问日志...

回答 2 投票 0

androidx.lifecycle.LiveDataReactiveStreams 类在版本 2.6.0 之后找不到

我刚开始玩LiveData。 我按照官方 Android 文档导入了不同的工件。一切都很好,直到我需要将 Observable 转换为 LiveData。但是

回答 1 投票 0

第一次运行 Room DB 查询会导致 Activity / Fragment onDestroy()

当我的应用程序运行时,StartFragment 在我的 Room DB 上运行 LiveData 查询以获取 PersonId。第一次数据库调用似乎创建/打开数据库,但 LiveData onChanged() 从未被调用并且

回答 0 投票 0

如何从 Observer android kotlin 保存值

我有一个 ROOM 数据库,我可以从中获取值。 我正在使用 Observer 来获取数据,但是有一个问题。我的 Fragment 中有一个全局变量 availability ,我想存储 v...

回答 1 投票 0

使用 DataBinding 和 LiveData 更新 Recyclerview 数据项

将项目添加到回收站视图并处理增量更新 我已经有了一个可行的解决方案。

回答 0 投票 0

使用Live Data作为参数和使用return有区别吗?

我在 ViewModel 中创建函数以避免在使用 Flow 和 LiveData 时重复。在示例中,我创建了一个扩展函数,如下所示。在和我的朋友交谈时,我们开始考虑

回答 1 投票 0

使用 MutableLiveData 和具有多个图像的 LiveData 实现 ViewModel

下面的代码使我能够从手机图片库中最多选择 4 张图片。但是,我需要有关视图模型代码的帮助。如果选择一张图像并且手机配置发生变化,则图像

回答 0 投票 0

Kotlin - 在运行函数之前等待多个 LiveData 被观察

我正在使用 viewModel 从房间数据库中提取实时数据。我有 2 个从我的 viewModel 中提取的 LiveData,然后我将运行一个函数从我的服务器中提取数据。我需要两个值都...

回答 2 投票 0

Flow<Set<CategoriesItemResponse>> 重新排序内容后似乎没有发出新的转换值

我正在使用首选项 DataStore 来保存一组简单的 CategoriesItemResponse(我知道这不是一个好的做法,但这不是重点)。我有流量 我正在使用首选项数据存储来保存一组简单的CategoriesItemResponse(我知道这不是一个好的做法,但这不是重点)。我的 Flow<Set<CategoriesItemResponse>> 中有一个 UserPreferencesRepository,它通过各种 ViewModels 公开以供观察。 此外,我还提供了在 Set 中添加、删除和重新排序类别项的方法,以便每个操作都反映在流中。添加/删除功能似乎工作正常,观察流程的屏幕确实会立即对数据的变化做出反应。不过,重新排序逻辑的流程似乎有缺陷。 这是我的存储库: class UserPreferencesRepository(private val context: Context) { val userFavoriteCategories = context.dataStore.data.map { prefs -> val categoriesJson = prefs[PreferenceKeys.userFavoriteCategories] println("categories flow read JSON in favorites flow = $categoriesJson") categoriesJson?.convertToSetObject<CategoriesResponseItem>() ?: emptySet() } suspend fun addCategoryToUserFavorites(category: CategoriesResponseItem) { withContext(Dispatchers.IO) { try { context.dataStore.edit { preferences -> val categoriesJson = preferences[PreferenceKeys.userFavoriteCategories] val categories: Set<CategoriesResponseItem> = categoriesJson?.convertToSetObject() ?: emptySet() val updatedCategories = categories.toMutableSet().apply { add(category) }.toSet() val updatedJSON = Gson().toJson(updatedCategories) println("Updated JSON in add category: $updatedJSON") preferences[PreferenceKeys.userFavoriteCategories] = updatedJSON } } catch (e: Exception) { e.printStackTrace() Log.e( UserPreferencesRepository::class.java.simpleName, "Failed to add category $category to user preferences!" ) } } } suspend fun removeCategoryFromUserFavorites(category: CategoriesResponseItem) { withContext(Dispatchers.IO) { try { context.dataStore.edit { preferences -> val categoriesJson = preferences[PreferenceKeys.userFavoriteCategories] val categories: Set<CategoriesResponseItem> = categoriesJson?.convertToSetObject() ?: emptySet() val updatedCategories = categories.toMutableSet().apply { remove(category) }.toSet() val updatedJSON = Gson().toJson(updatedCategories) println("updated JSON in remove category: $updatedJSON") preferences[PreferenceKeys.userFavoriteCategories] = updatedJSON } } catch (e: Exception) { e.printStackTrace() Log.e( UserPreferencesRepository::class.java.simpleName, "Failed to remove category $category to user preferences!" ) } } } suspend fun reOrderCategories(from: Int, to: Int) { withContext(Dispatchers.IO) { try { context.dataStore.edit { preferences -> val categoriesJson = preferences[PreferenceKeys.userFavoriteCategories] val categories: Set<CategoriesResponseItem> = categoriesJson?.convertToSetObject() ?: emptySet() val updatedCategories = categories.toMutableList().apply { add(to, removeAt(from)) }.toSet() val updatedJSON = Gson().toJson(updatedCategories) println("updated JSON in reOrder categories: $updatedJSON") preferences[PreferenceKeys.userFavoriteCategories] = updatedJSON } } catch (e: Exception) { e.printStackTrace() Log.e( UserPreferencesRepository::class.java.simpleName, "Failed to persist reordering from $from to $to for user categories" ) } } } } 调用这些函数同时暴露流程的viewmodel是这样的: class CategoriesViewModel(private val userPreferencesRepository: UserPreferencesRepository) : ViewModel() { //todo:sp consider getting these dynamically private val hardcodedCategories = listOf( CategoriesResponseItem( id = -1, name = "FRUITS AND VEGETABLES", registrationType = CategoryType.PREMIUM.ordinal, isSuggested = false ), CategoriesResponseItem( id = -2, name = "NUTS, NUT PRODUCTS AND SEEDS", registrationType = CategoryType.PREMIUM.ordinal, isSuggested = false ), CategoriesResponseItem( id = -3, name = "FRUITS AND VEGETABLES", registrationType = CategoryType.PREMIUM.ordinal, isSuggested = false ), CategoriesResponseItem( id = -4, name = "FRUITS AND VEGETABLES", registrationType = CategoryType.PREMIUM.ordinal, isSuggested = false ) ) private var backingCategories = emptyList<CategoriesResponseItem>() val userSavedCategories = userPreferencesRepository.userFavoriteCategories.transform { val mutableCategories = it.toMutableSet() mutableCategories.addAll(hardcodedCategories) backingCategories = mutableCategories.toList() println("transform called") emit(mutableCategories.toSet()) } fun removeCategory(category: CategoriesResponseItem) { viewModelScope.launch(Dispatchers.IO) { userPreferencesRepository.removeCategoryFromUserFavorites(category) } } fun onItemReorder(from: ItemPosition, to: ItemPosition) { viewModelScope.launch(Dispatchers.IO) { println("reorder in VM called") userPreferencesRepository.reOrderCategories(from.index, to.index) } } fun isCategoryDraggable(draggedOver: ItemPosition, dragging: ItemPosition): Boolean { return backingCategories .getOrNull(draggedOver.index)?.registrationType == CategoryType.FREE.ordinal } } 我的问题似乎是 UI 似乎没有对重新排序做出反应,尽管调用了存储库的重新排序方法并且更新了首选项。 transform() 用于将用户的数据与仅前端需要的一些“高级”类别样本相结合。 Logcat 似乎表明流程一直运行到变换 lambda 内的println("transform called"),但除非我重新访问页面,否则 UI 看不到项目顺序的变化。 这是 UI 代码: @OptIn(ExperimentalFoundationApi::class) @Composable fun EditCategoriesScreen( navController: NavController, categoriesViewModel: CategoriesViewModel ) { val userCategories by categoriesViewModel.userSavedCategories.collectAsState(initial = emptySet()) val reorderState = rememberReorderableLazyListState( onMove = { from, to -> categoriesViewModel.onItemReorder(from, to) }, canDragOver = categoriesViewModel::isCategoryDraggable ) Column(Modifier.fillMaxSize()) { Column( Modifier.weight(1f) ) { SearchFieldAsButton(modifier = Modifier.padding(top = 25.dp)) { navController.navigate(Screens.ADD_CATEGORIES.navRoute) } LazyColumn( state = reorderState.listState, modifier = Modifier .padding(vertical = 16.dp) .reorderable(reorderState) .animateContentSize(), verticalArrangement = Arrangement.spacedBy(15.dp), userScrollEnabled = true, ) { println("categories in UI = ${userCategories.toList()}") itemsIndexed( userCategories.toList(), key = { _, item -> item.hashCode() }) { index, category -> if (CategoryType.values()[category.registrationType] == CategoryType.FREE) { ReorderableItem( reorderableState = reorderState, key = category.hashCode() ) { SwipeableUnlockedCategoryItem( modifier = Modifier .animateItemPlacement() .padding(horizontal = 12.dp) .detectReorderAfterLongPress(reorderState), displayNumber = 0, percentageNumber = 0, categoryName = category.name, onDelete = { categoriesViewModel.removeCategory(category) } ) } } else { val isComingSoonItem = index in (userCategories.size - 2 until userCategories.size) LockedCategoryItem( modifier = Modifier .animateItemPlacement() .padding(horizontal = 12.dp), displayNumber = 0, percentageNumber = 0, categoryName = category.name, isComingSoon = isComingSoonItem ) } } } } Column( modifier = Modifier .wrapContentHeight() .background( brush = Brush.verticalGradient( endY = 90f, colors = listOf( colorResource(id = R.color.white).copy(alpha = 0.2f), colorResource(id = R.color.white) ) ) ), horizontalAlignment = Alignment.CenterHorizontally ) { Spacer(Modifier.height(24.dp)) Text( modifier = Modifier .fillMaxWidth() .padding(start = 42.dp, end = 46.dp), text = stringResource(id = R.string.sample_text), textAlign = TextAlign.Center, style = MaterialTheme.typography.bodySmall ) Spacer(Modifier.height(16.dp)) FoodakaiButton( modifier = Modifier .fillMaxWidth() .height(50.dp) .padding(start = 16.dp, end = 16.dp), text = stringResource(R.string.more_insights_text), fontSize = 18.sp ) { navController.navigate(Screens.MORE_INSIGHTS.navRoute) } Spacer(Modifier.height(8.dp)) Image( modifier = Modifier .padding(top = 14.dp, bottom = 4.dp) .clickable { navController.navigate(Screens.ADD_CATEGORIES.navRoute) }, painter = painterResource(id = R.drawable.plus_icon), alignment = Alignment.Center, contentDescription = stringResource(R.string.add_category_icon_content_desc) ) Text( text = stringResource(R.string.add_a_category_text), style = MaterialTheme.typography.labelMedium ) Spacer(modifier = Modifier.height(24.dp)) } } } 第一次访问编辑页面时,我们得到以下日志: UI 中的类别 = [] category flow read JSON in favorites flow = [{"id":12,"isSuggested":true,"name":"糖果","registrationType":0},{"id":13,"isSuggested":true,"name":"肉 和肉类产品(家禽除外)","registrationType":0}] UI 中的类别 = [实际组合列表] 现在拖动项目并重新排序后,我们可以看到首选项已更新,但 UI 不会反映重新排序,除非我们重新访问页面。以下是拖动项目后的日志: 在 VM 中重新排序 更新了 reOrder 类别中的 JSON: [{"id":13,"isSuggested":true,"name":"肉类和肉类产品(其他 比 家禽)","registrationType":0},{"id":12,"isSuggested":true,"name":"Confectionery","registrationType":0}] <--- now "Meat..." is first category flow read JSON in favorites flow = [{"id":13,"isSuggested":true,"name":"肉类和肉类产品(其他 比 家禽)","registrationType":0},{"id":12,"isSuggested":true,"name":"Confectionery","registrationType":0}] 转换称为 这里没有“UI 中的类别”日志条目。我哪里搞砸了? 我猜你的问题来自collectAsState,因为它只会触发对使用相等性检查的新的不同值的重组。 尽管 Sets 是可迭代的,并且某些实现确实保留了您使用该顺序创建它们的顺序,但实际上并不是 Set 合同的一部分。 “重新排序”的集合是相等的,因此不会发出新状态。 如果项目安排很重要userSavedCategories必须产生一些索引:aList.

回答 1 投票 0

© www.soinside.com 2019 - 2024. All rights reserved.