Android ListView Adapter错误调用notifyDataSetChanged,Android bug?

时间:2015-04-22 18:40:32

标签: java android android-listview baseadapter notifydatasetchanged

在我一直在努力的应用中,我有一个自定义课程DeviceListAdapter,其中BaseAdapter传递给我的ListView。在我的DeviceListAdapter课程中,我保留了自己的ArrayList<Device>,用于生成View getView(... )的列表视图。每当应用导致数据发生变化时,我都会使用DeviceListAdapter中的自定义方法更新ArrayList<Device>以反映更改。我已经使用调试器和许多print语句检查数据是否按照我预期的方式更改,添加和删除指定的Device个对象。但是,在每次更改数据后,我也会调用notifyDataSetChanged(),但在UI上没有任何元素会更新。在调试器中,我发现在调用notifyDataSetChanged()后,getView(... )方法未被调用,这解释了为什么ListView没有被重绘。为了找出原因,我使用了调试器&#34;进入&#34;函数跟踪程序执行进入android框架的位置,因为我已经下载了SDK源代码。我发现的非常有趣。执行的路径是这样的:

DeviceListAdapter.notifyDataSetChanged()
BaseAdapter.notifyDataSetChanged()
DataSetObservable.notifyChanged()
AbsListView.onInvalidated()

enter image description here enter image description here enter image description here enter image description here

而是调用onChanged()方法,它跳过轨道并在onInvalidated()方法到达AbsListView后执行。最初我认为这是一个错误,调试器可能读错了行号,但我重新启动了我的Android Studio以及完全卸载并重新安装了应用程序,但结果是一样的。任何人都可以告诉我这是否是Android架构的合法问题,或者调试器是否不可靠,无法跟踪我自己的项目文件之外的执行?

有关notifyDataSetChanged()的实施的更多信息...我创建了覆盖BaseAdapter notifyDataSetChanged()的本地方法,以便设置布尔标志{{1}我的mForceRedraw内部是否应该强制重绘我的列表条目。在DeviceListAdapter方法中,我通常会检查第二个参数getView(... )是否为空,如果是,那么我重绘视图,如果没有,那么我将convertView传递给它并返回它。但是,当&#39; mForceRedraw&#39;是的,我永远不会返回View convertView,我明确地重绘了视图。出现的问题是由我之前的担忧造成的,即我执行convertView后未调用getView()

编辑:这是我notifyDataSetChanged()的代码段:

DeviceListAdapter

2 个答案:

答案 0 :(得分:1)

notifyDataSetChanged()存在许多错误,如果您尝试对列表数据进行一些复杂的工作,通常会出现错误。

大多数情况下,这是因为该方法是懒惰的,无法区分更改,因此要避免此问题,请使用以下方案测试代码:

  1. 删除更改行
  2. 致电notifyDataSetChanged()
  3. 在索引处添加更改的行
  4. 再次致电notifyDataSetChanged()
  5. 并告诉我它是否解决了你的问题。

    编辑:放入适配器代码后,我看到了代码中的缺陷。

    对不起迟到的回复:

    convertView是您在初始化之前填充的视图。

    当在方法getView()中获得convertView的实例时,必须在返回之前填充它。 所以要明确,做这样的事情:

    public View getView(final int position, View convertView, ViewGroup parent) {
        View view;
        if (convertView == null) //Regenerate the view
        {
            /* Instantiate your view */
        } else {
            view = convertView;
        }
        // populate the elements in view like EditText, TextView, ImageView and etc
        return view;
    }
    

答案 1 :(得分:1)

您在适配器中并且调用通知数据集已更改。理想情况下甚至不需要。因为正在修改适配器内部使用的数据集。适配器的getView方法将每当需要渲染视图时总是被调用。

convertView方法是单独回收视图(而不是数据)。它只是为您提供了昂贵的视图通胀过程的替代方法。

那么您的代码应该是什么:

public View getView(final int position, View convertView, ViewGroup parent) {
            LinearLayout view;
            if (convertView == null) //Regenerate the view
            {

              /* inflate Draws my views */

            } else 
            {
                view = (LinearLayout) convertView;

            }

            //repopulate this view with the data that needs to appear at this position using getItem(position)


            return view;
        }