首页 > 解决方案 > 如何在 android RecyclerView 中获取列表以在修改其显示内容的活动后更新?

问题描述

我已经看到了一些 RecyclerView 示例,它们只是在单击侦听器中修改了一个项目。我的问题是我从单击一个项目开始一个活动,并且该活动可以从列表中更改或删除单击的项目。所以需要在活动完成后更新视图。这段代码主要来自另一个开发人员,将序列化的项目和项目的位置作为额外数据传递给活动。该位置旨在用于稍后更新视图。

但是,我发现了这些评论:

"不要把位置当作固定的,只能立即使用,稍后调用 holder.getAdapterPosition() 查找。当数据集中项的位置发生变化时,RecyclerView 不会再次调用 onBindViewHolder,除非该项本身失效或新的位置是无法确定的,因此在该方法内部获取相关数据项时,只能使用位置参数,不能保留副本,如果以后需要某个项的位置(例如,在点击中)侦听器),使用 getAdapterPosition() 将具有更新的适配器位置。”

在适配器中:

@Override
public void onBindViewHolder (@NonNull ItemAdapter.MyViewHolder holder, final int position)
{
    final Item item = items.get(position);
    holder.itemTitle.setText(item.getTitle());
    holder.lay_item.setOnClickListener (new View.OnClickListener () {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(context, ItemDetailActivity.class);
            intent.putExtra("Item", item);
            intent.putExtra("position", position);
            context.startActivity (intent);
            // TODO is this the place to refresh the view?
            //holder.getAdapterPosition();
        }
    });
}

对于活动:

Item currentItem;

protected void onCreate (Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_item_detail);

    currentItem = (Item)getIntent().getSerializableExtra("Item"));
    position = getIntent().getExtras().getInt("position");
    ... 
}

我意识到视图持有的对象被序列化为额外的数据,因此活动中的currentObject不是同一个对象。

我不知道他们为什么那样做。如果这是常态,请告诉我如何更新列表视图以更改活动中的对象。如果这不是常态,应该怎么做?这就是问题的基础,如标题中所述:如何在 android RecyclerView 中获取列表以在修改其显示内容的活动后更新?

在 Activity 中,有一个用于“保存”按钮的单击侦听器来更新数据库:

    btn_save.setOnClickListener (new View.OnClickListener () {
        @Override
        public void onClick(View v) {
            // ... stuff that updates the item attributes from the view elements... 
            // Save it. It is this object that should then be in the list in the RecyclerView.
            try
            {
                MyApp.getDatabase().updateItem(item);
                // TODO: This might work if currentItem was actually the one in the list
                //adapter.notifyDataSetChanged();
            }
            catch (PersistenceException ex)
            {
                // notify user of failure
                Toast.makeText (EditItemActivity.this, getResources().getString(R.string.item_update_fail), Toast.LENGTH_LONG).show ();
                finish();
                return;
            }

            Toast.makeText(EditItemActivity.this, getResources().getString(R.string.item_update_success), Toast.LENGTH_LONG).show ();
            finish ();
        }
    });

适配器是在这样的片段中创建的(其中“rv_items”是 RecyclerView):

        adapter = new ItemAdapter(itemList, getActivity());
        rv_items.setAdapter(adapter);

Item 类声明为:class Item implements Serializable

标签: androidandroid-recyclerview

解决方案


一般来说,任何时候你在谈论“修改 RecyclerView”,这都暗示你正在以错误的方式看待事物。您应该始终考虑修改数据,然后意识到 RecyclerView 只是显示该数据的一种方式。当然,您需要notifyDataSetChanged()在修改数据时调用方法,以便 RecyclerView 可以知道更新其显示以获取更改,但您仍然应该始终首先考虑数据。

话虽如此,这里问题的根源是您需要某种方法来唯一地标识您的数据项列表中的项。一般来说,我倾向于在这里使用某种唯一 ID(而不是位置)。然后,当您的第二个活动完成并返回其结果时,您可以使用该 ID 更新您的数据列表并将更改分派到 RecyclerView。

有了这一切,你会有这样的事情:

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == MY_REQUEST) {
        if (resultCode == Activity.RESULT_OK && data != null) {
            String id = data.getStringExtra("id");

            for (int i = 0; i < items.size(); ++i) {
                if (items.get(i).getId().equals(id)) {
                    // the item at position i was updated.

                    // insert your code here...

                    // at the end, notify the adapter
                    adapter.notifyItemChanged(i);
                }
            }
        }
    }
}

推荐阅读