【问题标题】:Android: notifydatachanged not updating listviewAndroid:notifydatachanged 不更新列表视图
【发布时间】:2014-10-23 22:21:17
【问题描述】:

当用户单击列表视图上的项目时,我正在手动更改所选列表视图项目的背景颜色。我计划改变的不仅仅是背景(最终是图标等等),因此我需要列表视图来重绘自己。

问题是当我 notifyDataChanged 没有任何反应。由于我在函数中放置了日志,当单击项目时,我可以验证是否触发了 onItemClick,并且还可以验证对适配器的 notifyDataSetChanged 调用。

我希望每个位置都应该再次调用“getView”,在这些位置数据链接到视图。但这并没有发生。没有发生任何事情的迹象。我在这里错过了什么?

class MyOnItemClickListener implements AdapterView.OnItemClickListener{

    @Override
    public void onItemClick(final AdapterView<?> parent, View view, 
            final int position, long id) {

            Log.i(TAG, "listview on click " + position);

            MyListAdapter adapter = (MyListAdapter) parent.getAdapter();

            adapter.mSelected = position;
            adapter.notifyDataSetChanged();
    }
}


class MyListAdapter extends BaseAdapter{

    public List<String> mTxtContents;

    public int mGroupCount;
    public int mSelected;

    public void setData(List<String> txtContents){

        mTxtContents = txtContents;
        mGroupCount = txtContents.size();
    }

    @Override
    public void registerDataSetObserver(DataSetObserver observer) {
        // TODO Auto-generated method stub

    }

    @Override
    public void notifyDataSetChanged() {

        Log.i(TAG, "notify data set changed");

        // TODO Auto-generated method stub
        super.notifyDataSetChanged();
    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {
        // TODO Auto-generated method stub

    }

    @Override
    public int getCount() {

        Log.i(TAG, "nva panel group count " + mGroupCount);

        return mGroupCount;
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public boolean hasStableIds() {
        // TODO Auto-generated method stub
        return false;
    }

    @SuppressLint("InflateParams")
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        Log.i(TAG, "get view, " + position);

        if(convertView == null){
            LayoutInflater li = LayoutInflater.from(getActivity());
            convertView = li.inflate(R.layout.lvitem_navpanel, parent, false);
        }

        TextView tv = (TextView) convertView.findViewById(R.id.tv_txtData);
        tv.setText(mTxtContents.get(position));

        if(mSelected == position){
            convertView.setBackgroundColor(Color.parseColor("#00FF00"));
        }else{
            convertView.setBackgroundColor(getResources().getColor(android.R.color.transparent));
        }

        return convertView;
    }

    @Override
    public int getItemViewType(int position) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public int getViewTypeCount() {
        // TODO Auto-generated method stub
        return 1;
    }

    @Override
    public boolean isEmpty() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean areAllItemsEnabled() {
        // TODO Auto-generated method stub
        return true;
    }

    @Override
    public boolean isEnabled(int position) {
        // TODO Auto-generated method stub
        return true;
    }
}

【问题讨论】:

  • 您需要完成 MyListAdapter 的 getItem(int position) 的实现。此外,除非需要,否则不要覆盖 registerDataSetObserver 和 unregisterDataSetObserver。 ListView 使用这种观察者机制来了解您何时调用了 notifyDataSetChanged,但您对这些方法的空实现会阻止这种情况发生。只需让 BaseAdapter 为您处理。
  • 我不认为你的答案会起作用......但它确实起作用了:) 起作用的部分是删除 register/unreigster 函数的覆盖。删除 getItem() 函数并没有影响它,因为当我将 Log 放在那里时,它永远不会被调用。 Eclipse 自动填充了注销/注册函数而不调用超级函数,我猜这破坏了列表视图。如果您想将其作为答案,我会将其标记为正确。

标签: android listview


【解决方案1】:

修改后再次尝试设置适配器。像这样:

MyListAdapter adapter = (MyListAdapter) parent.getAdapter();
adapter.mSelected = position;
parent.setAdapter(adapter);

对 setAdapter 的新调用将清除回收器。

编辑:

我不确定您为什么要使用上面发布的模式(在我看来,这似乎是不必要的样板和处理,但也许您有特殊需要),以下内容可能对您有所帮助

在您的 OnClick 侦听器中,您可以执行类似的操作

TextView txtView = (TextView)listView.getChildAt(position);
txtView.setBackgroundColor(Color.RED);
txtView.setText("New Text");

这将自动将更改应用到您的列表项。

如果您需要刷新整行,您可以这样做

View view = list.getChildAt(position);
list.getAdapter().getView(position, view, list);

Source

【讨论】:

  • 这也有效,所以 +1。使用当前设置为强制调用 getView 的适配器设置列表视图,并重绘所有子视图。不过,我不能将此标记为最佳答案,因为我不知道这样做的成本。例如,缓存在 listView 的子项(例如 viewHolders)中的值是否丢失,状态信息,例如在可扩展列表视图的情况下扩展了哪些组,或者重新设置适配器的开销(即使它相同)适配器)。
  • 还有哪些对你有用的东西?除了重置适配器?不过祝你好运。
  • @Michael Krause 在 cmets 中提供的答案有效。问题是 Eclipse 建议通过为注销/注册数据观察者创建存根来覆盖“未实现的方法”,而不调用超级函数。
  • 那么如果没有这些覆盖,一个简单的 notifyDataSetChanged() 就足以显示新的背景颜色?只是想知道科学:)
  • 是的,一个简单的 notifyDataSetChanged() 就可以了。这就是它的工作方式:) 它通知它所附加的adapterView,它的子视图需要刷新。您会认为无效视图的工作方式类似,但它不会......它不会导致子视图重新查询他们的数据源,只是用他们当前持有的数据重绘自己(如果有的话)。
猜你喜欢
  • 2017-05-21
  • 2011-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多