【问题标题】:notifyDataSetChanged in viewHolder classviewHolder 类中的 notifyDataSetChanged
【发布时间】:2019-07-16 11:37:41
【问题描述】:

我可以在 view Holder 中使用 notifyDataSetChanged() 吗?

class ItemViewHolder(context: Context?, view: View) : RecyclerView.ViewHolder(view) {

       func update(){
           // ...
           // i need to update adapter for example
           adapter.notifyDataSetChanged()
       }

}

【问题讨论】:

  • 是的,即使没有 adapter 对象,如果您的 viewHolder 是 Inner 类并且 update() 正在执行某些操作,您也可以。您面临的问题是什么?
  • @ADM 我不喜欢将适配器传递给内部视图支架。
  • 你不必......只要让ItemViewHolder成为适配器类的内部类。

标签: android kotlin android-recyclerview adapter


【解决方案1】:

将您的class 转换为inner class 无疑是一种方法。我还会考虑将您的ViewHolder 引用传递给您提出的ListenerCallback 接口(或一组函数)。如果您决定将 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)
    }

}

然后在其他地方处理该更新。例如,在适配器或 ViewModel 逻辑中:

fun onCreateViewHolder(...) {
    val viewHolder = ViewHolder(...) { /* do update */ }
}

这让我们处于现在适配器既负责将数据映射到视图以及管理该数据的状态的地步......这不是很干净。

我喜欢这样做:

class Adapter(private val updateItem: (Item) -> Unit) {
    fun onCreateViewHolder(...) {
        return ViewHolder(...) { updateItem(items[it]) }
    }
}

我们在更合理的地方处理数据操作。这里:

  1. ViewHolder 将单击或更新事件映射到它所持有的项目的位置
  2. 适配器将位置映射到实际数据项
  3. Presentation 对象(例如架构组件 ViewModel)(向适配器提供 lambda 的人)执行操作。 (更多内容见下文)

在这种情况下,您的 notifyDataSetChanged 将由演示者处理,然后反馈给适配器。例如,也许您在 Adapter 上有一个名为 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) { ... }
}

您的 Activity(您在其中设置适配器)随后可以观察到对此的更改:

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),并利用 lambdas 来确保我们不直接依赖于我们不需要的东西成为(DIP)。

【讨论】:

    【解决方案2】:

    在你的 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;
                }
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-09
      相关资源
      最近更新 更多