我可以在视图持有人中使用notifyDataSetChanged()吗?
class ItemViewHolder(context: Context?, view: View) : RecyclerView.ViewHolder(view) {
func update(){
// ...
// i need to update adapter for example
adapter.notifyDataSetChanged()
}
}
答案 0 :(得分:2)
将class
转换为inner class
当然是一种方法。我还将考虑向您的ViewHolder
传递对您提出的Listener
或Callback
接口(或一组函数)的引用。如果您决定将ViewHolder移至其他文件或将其移至适配器之外,则这将使重构更加容易。当我们从ViewHolder中删除数据管理并将其转移到其他地方时,它也更好地遵守了“单一责任原则”。
例如:
class ViewHolder(
private itemView: View
private val onDataSetChanged: () -> Unit
) : RecyclerView.ViewHolder(itemView) {
fun onUpdate() {
// Perform changes...
onDataSetChanged()
}
}
尽管ViewHolder会操纵这样的数据项,但对我来说有点奇怪。通常,这些仅保留项目的位置信息和视图状态,而不保留项目本身。另一种方法可能是将位置信息传递给更新lambda:
class ViewHolder(
private itemView: View
private val onDataSetChanged: (Int) -> Unit
) : RecyclerView.ViewHolder(itemView) {
fun onShouldUpdate() {
if (adapterPosition == RecyclerView.NO_POSITION) return
onDataSetChanged(adapterPosition)
}
}
然后在其他地方处理该更新。例如,在Adapter或ViewModel逻辑中:
fun onCreateViewHolder(...) {
val viewHolder = ViewHolder(...) { /* do update */ }
}
这使我们处于一个阶段,现在适配器负责将数据映射到视图以及管理数据的状态……这不是很干净。
这就是我喜欢的方式:
class Adapter(private val updateItem: (Item) -> Unit) {
fun onCreateViewHolder(...) {
return ViewHolder(...) { updateItem(items[it]) }
}
}
我们在更合理的地方处理数据的地方。在这里:
在这种情况下,演示者将处理您的notifyDataSetChanged,然后将其反馈到适配器中。例如,也许您在适配器上有一个名为setData(items: List<Item>)
的方法。当有新的项目列表可用时,演示者通知适配器,该适配器将设置项目:
// In your adapter
fun setData(newItems: List<Item>) {
val oldItems = items
items = newItems
notifyDataSetChanged()
// Alternatively, utilize DiffUtil
}
您的ViewModel然后可以使用LiveData
公开一个可观察的字段。
class MyViewModel : ViewModel() {
val items: LiveData<List<Item>>
fun updateItem(item: Item) { ... }
}
您的活动(在其中设置适配器的位置)可以观察到对此的更改:
val adapter = Adapter(viewModel::updateItem)
// Note you could probably use a method reference instead of a lambda.
viewModel.items.observe(this) { adapter.setItems(it) }
我希望这种帮助有助于概述该方法。我可以整天谈论这件事,所以随时问任何问题。这里的想法是,我们正在明确地分离我们的关注点(SRP),消除了将整个适配器移交给ViewHolder(ISP)的需要,并利用了lambda来确保我们不直接依赖于不需要的东西成为(DIP)。
答案 1 :(得分:1)
在您的 View Holder 中实现一个 onclick 事件侦听器,然后像这样删除一个 View holder。
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.musicPlay:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setType("audio/*");
intent.setData(Uri.parse(mItem.getContentUri()));
context.startActivity(intent);
break;
case R.id.musicShare:
Toast.makeText(context, "Music is shared", Toast.LENGTH_SHORT).show();
break;
case R.id.musicDelete:
if (context.getContentResolver().delete(Uri.parse(mItem.getContentUri()), null, null)>0)
Toast.makeText(context, mItem.getTitle() + " is deleted", Toast.LENGTH_SHORT).show();
MediaScannerConnection.scanFile(context, new String[]{
mItem.getData()},
null, new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
mValues.remove(mItem);
notifyDataSetChanged();
}
});
break;
}
}