在 notifyDataSetChanged 之后焦点发生变化之前,ListView 不会显示变化

ListView does not show changes until focus changes after notifyDataSetChanged

我有一个 AlertDialog,其中 ListView 设置为多选。它上面还有一个 Button

Button 打开另一个 AlertDialog 如果确定将从 ListView 的数据集中删除所选项目,然后告诉列表视图的适配器数据集已使用 notifyDataSetChanged() 方法更改。

这一切都很好,除了一件事。 ListView 在我与某些东西互动之前不会更新它的内容。然后更新为正确的数据。

这不是什么大问题,但我真的希望 ListView 立即显示正确,而不是在焦点改变之后。

代码:

Button remove = (Button) view.findViewById(R.id.btn_remove_questions_edit_rack);
    final Context con = this;
    remove.setOnClickListener(new OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            Builder warnBuild = new Builder(con);
            warnBuild.setMessage(R.string.question_deletion_warning);
            warnBuild.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener()
            {
                @Override
                public void onClick(DialogInterface dialog, int which)
                {
                    SparseBooleanArray checked = list.getCheckedItemPositions();
                    for (String s : keys)
                    {
                        int i = keys.indexOf(s);
                        if (checked.get(i))
                        {
                            toRemove.add(map.get(s));
                            map.remove(s);
                        }
                    }
                    keys.clear();
                    keys.addAll(map.keySet());
                    ((ArrayAdapter) list.getAdapter()).notifyDataSetChanged();
                    list.clearChoices(); //This makes sure the selection is cleared, if it isn't, some of the other items (those that now has the index of the selected items) will be selected when the View refreshes.
                    dialog.dismiss();
                }
            });

            //Negative button here, not relevant.
        }
    });

其中 mapkeys 是:

final HashMap<String, QualityQuestion> map = new HashMap<>();
//I add items to the map
final ArrayList<String> keys = new ArrayList<>(map.keySet());

toRemove 是我存储要在按下原始 AlertDialog 上的确定按钮时从它们所在的实际对象中删除的项目的地方。

这就是我首先填充 ListView 的方式:

final ListView list = (ListView) view.findViewById(R.id.list_questions_edit_rack);
    list.setAdapter(
            new ArrayAdapter<String>(this,
                    android.R.layout.simple_list_item_activated_1,
                    keys));

我已经尝试过 list.invalidateViews()list.invalidate 以及我在 SO 上发现的与我的问题类似的其他问题。但是 none 有什么不同。我怀疑我的问题与他们的不同,因为我的项目显然已更新,只需改变对原始 AlertDialog 的关注即可看到更改。

如何让 ListView 显示焦点更改后立即安装的数据源中的更改?

您可以调整它,将焦点授予另一个视图,然后请求返回:

view.requestFocus();

您还可以使用:

view.requestFocusFromTouch();

通过调用

((ArrayAdapter) list.getAdapter()).notifyDataSetChanged();

您得到一个新的适配器,它几乎肯定与您最初用于填充列表的匿名适配器不同。

另请参阅 ListView.getAdapter()

的文档

Returns the adapter currently in use in this ListView. The returned adapter might not be the same adapter passed to setAdapter(ListAdapter) but might be a WrapperListAdapter.

从这个新适配器的角度来看,数据集没有改变,因为改变发生在它被实例化之前。

要解决您的问题,请将您的列表和列表适配器成员设为 activity class(或您希望它们保持活动状态的范围):

private ArrayList<String>    keys;
private ArrayAdapter         myAdapter;
private ListView             list;

然后在你的"onCreate()"

keys = ...;     // initialization of ArrayList with the needed data 
myAdapter = new ArrayAdapter<String>(this,
                    android.R.layout.simple_list_item_activated_1,
                    keys);
list = (ListView) view.findViewById(R.id.list_questions_edit_rack);
list.setAdapter(myAdapter);

这样,在你的"OnClickListener"你可以通知"myAdapter":

keys.addAll(map.keySet());
myAdapter.notifyDataSetChanged();

希望这对您有所帮助:)