此bounty已结束。回答此问题可获得+50声望奖励。奖励宽限期将在15小时后结束。jane希望引起更多人关注此问题。
我有一个片段,其中使用创建一个特定类别的预算如下:
下面是它的工作原理:用户在NewBudgetFragment中添加新预算项。该项将显示在recyclerview的BudgetFragment中。预算项具有amountSpent变量,用户每次添加新事务时都应更新该变量(这发生在另一个片段中)。但是在创建预算项目之后,如果用户在该特定类别上花钱,amountSpent在recyclerview项中没有得到更新。我在BudgetAdapter中同时使用了LiveData和DiffUtil,但我不知道为什么它没有得到更新。
下面是预算适配器:
class BudgetAdapter() : ListAdapter<Budget, BudgetAdapter.BudgetViewHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BudgetViewHolder {
val binding =
BudgetItemLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return BudgetViewHolder(binding)
}
override fun onBindViewHolder(holder: BudgetViewHolder, position: Int) {
val currentItem = getItem(position)
holder.bind(currentItem, position)
}
class BudgetViewHolder(val binding: BudgetItemLayoutBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(budget: Budget, position: Int) {
binding.apply {
tvBudgetName.text = budget.name
tvBudgetLimit.text = budget.limit.toString()
tvAmountSpent.text = budget.amountSpent.toString()
tvPercentageSpent.text = ((budget.amountSpent/budget.limit)*100).toInt().toString() + "%"
}
}
}
class DiffCallback : DiffUtil.ItemCallback<Budget>() {
override fun areItemsTheSame(oldItem: Budget, newItem: Budget): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Budget, newItem: Budget): Boolean {
return oldItem == newItem
}
}
}
以下是创建新预算项目的方法:新预算片段:
...
viewModel.transactions.observe(viewLifecycleOwner) { it ->
transactionList = it.filter { it.category == listCategory[selectedCategoryIndex].name }
amountSpent = transactionList.sumOf { it.amount }
}
...
if (budgetName.isNotEmpty() && budgetLimit.isNotEmpty() && budgetCategory != null) {
viewModel.addBudget(
name = budgetName,
limit = budgetLimit.toDouble(),
amountSpent=amountSpent,
category = budgetCategory.name)
这是BudgetFragment.kt,其中适配器是:
class BudgetFragment : Fragment(R.layout.fragment_budget),BudgetAdapter.OnItemClickListener {
private lateinit var binding: FragmentBudgetBinding
private val viewModel: SharedViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentBudgetBinding.bind(view)
val budgetAdapter = BudgetAdapter(this)
val toolbar = binding.toolbar.root
toolbar.title = "Budget"
(requireActivity() as MainActivity).setSupportActionBar(toolbar)
binding.apply {
rvBudget.apply {
adapter = budgetAdapter
setHasFixedSize(true)
}
}
viewModel.budgets.observe(viewLifecycleOwner){
if(it.isNotEmpty()){
binding.rvBudget.visibility = View.VISIBLE
binding.tvNoBudget.visibility = View.INVISIBLE
}else{
binding.rvBudget.visibility = View.INVISIBLE
binding.tvNoBudget.visibility = View.VISIBLE
}
budgetAdapter.submitList(it)
}
binding.btAddBudget.setOnClickListener {
val action = BudgetFragmentDirections.actionBudgetFragmentToNewBudgetFragment()
findNavController().navigate(action)
}
}
2条答案
按热度按时间arknldoa1#
我试着在互联网上找到一些示例解决方案。肯定有一个,但是找不到。我发现其中很多都太短或太详细。所以我将在这里提供您所需要的。有一个涉及
RecyclerView
+LiveData
的标准化模式,所以在所有RecyclerView
+LiveData
的使用中都遵循这个模式。片段:
此处进行了一些重要更改:
必须在
onCreateView()
中使用.observe()
。不仅仅是在这个特定的情况下,但通常情况下,如果正确使用LiveData
,则永远不需要在任何其他位置调用.observe()
。viewLifecycleOwner
是用于观察LiveData
的正确LifecycleOwner
。(除非您创建了自定义适配器。)取决于用例,但通常每个RecyclerView
示例化一个适配器,即使您的数据随时间而更改。您应该交换数据,而不是整个适配器。我的适配器:
MyAdapter
应实现视图将使用的.submitList()
函数请注意,
notifyDataSetChanged()
实际上是向适配器发出更新视图的信号。wqsoz72f2#
假设Budget类是一个数据类,那么内容比较应该可以工作,所以我们应该不会遇到适配器和DiffUtil使用的对象本身的任何问题。
但是:
我看不到ViewModel代码-您是否使用submitList将相同的列表示例提交给适配器?例如,您是否每次都在ViewModel中修改私人列表中的项目,并在相同的动态数据上发布相同的列表?
如果是,则这可能是RecyclerView中的项目未被刷新的原因。您需要使用旧列表的内容创建新的列表示例,然后将其发布到LiveData上。
示例ViewModel,如果您不想覆盖“submitList”的行为,即清除以前的数据并添加新数据,然后自己调用notifiyDatasetChanged()