Override ListView getAdapter造成的后果

Override ListView getAdapter造成的后果

近期工作中,发现了一个bug,是和ListView Adapter有关的。产生了FC,描写叙述信息大约是

"The content of the adapter has changed but ListView did not receive a notification. Make sure the content of  your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(xxx) with Adapter(HeaderViewListAdapter)]"

它的大意是,Adapter内的数据发生了变化,可是UI却没有更新,您是否忘记调用了notifyDataSetChanged?

这实际上是一个很有误导的信息。普通情况下,我们不会忘记调用该函数的。可是假设我们不小心,从listview继承一个新的类,并override它的getAdapter方法,就可能会出问题了。

ListView是支持HeaderView和footerView的,即在listview的最初和最末尾的位置加入�一些特殊的view。它的实现方法,就是通过一个HeaderViewListAdapter。

HeaderViewListAdapter会包装一个Adapter,这个是由用户自己设置的。ListView中相应的代码是

    @Override
    public void setAdapter(ListAdapter adapter) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

        resetList();
        mRecycler.clear();

        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
            mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
        } else {
            mAdapter = adapter;
        }

ListView的getAdapter返回的是mAdapter,就可以能是一个HeaderViewListAdapter.

假设override getAdapter,并返回HeaderViewListAdapter内部包装的Adapter,就会出问题。也就是上面提到的FC.

这样的问题是怎么出现呢?

首先,这个异常抛出的位置,是在函数layoutChildren中,抛出的条件是mItemCount != mAdapter.getCount(),代码例如以下:

else if (mItemCount != mAdapter.getCount()) {
                throw new IllegalStateException("The content of the adapter has changed but "
                        + "ListView did not receive a notification. Make sure the content of "
                        + "your adapter is not modified from a background thread, but only from "
                        + "the UI thread. Make sure your adapter calls notifyDataSetChanged() "
                        + "when its content changes. [in ListView(" + getId() + ", " + getClass()
                        + ") with Adapter(" + mAdapter.getClass() + ")]");
            }

那么mItemCount的值是在哪里赋值呢?mItemCount不是ListView的成员,而是ListView的超超类:AdapterView的成员,这个值也是在DataObserver.onChanged中设置的,您可參考AdapterView的源代码:

class AdapterDataSetObserver extends DataSetObserver {

        private Parcelable mInstanceState = null;

        @Override
        public void onChanged() {
            mDataChanged = true;
            mOldItemCount = mItemCount;
            mItemCount = getAdapter().getCount(); //这里!注意使用方法getAdapter()

            // Detect the case where a cursor that was previously invalidated has
            // been repopulated with new data.
            if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
                    && mOldItemCount == 0 && mItemCount > 0) {
                AdapterView.this.onRestoreInstanceState(mInstanceState);
                mInstanceState = null;
            } else {
                rememberSyncState();
            }
            checkFocus();
            requestLayout();
        }

假设 getAdapter() != mAdapter就会发生故障:getAdatper返回的是mAdapter(即HeaderListViewAdapter),那么,mAdapter.getCount() == getAdapter().getCount() + header view count + footer view count.

出现上面的问题就在所难免了。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/119023.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Java集合篇:ConcurrentHashMap详解(JDK1.6)

    Java集合篇:ConcurrentHashMap详解(JDK1.6)

  • springboot 指定logback.xml文件的位置(springboot接收参数)

    学习了下psring的日志管理,具体的xml配置文件记录如下,方便以后参考。<?xmlversion="1.0"encoding="UTF-8"?><!–configuration根节点属性说明:scan:配置文件改

  • 修改asmx样式「建议收藏」

    修改asmx样式「建议收藏」今天看到一张图,asmx的WebService。长这样:当时就感觉有意思,这个页面风格和我们平时的不一样,我们平时的WebService长这样:我们如果在WebMetohd上面加注释,即[WebMethod(Description=”注释”)],那么长这样:那么问题就来了,第一张图里面的样式是如何实现的呢?在浏览器上进入调试模式观察,可以发现它的html和我们的有点不…

  • 校园网络拓扑图及配置_校园网防火墙

    校园网络拓扑图及配置_校园网防火墙该设计topo图(三层:核心、汇聚、接入),并加所有的配置命令。文章中的综合运用设计技术的单个技术如vlan划分、静态路由、OSPF、单臂路由(trunk/access)、DHCP、无线WLAN、Snooping、MSTP、VRRP、防火墙、DNSserver、ACL等。该topo适合了解并熟知单个组网技术的小伙伴,并想学习将单个技术组合应用的小伙伴,使用场景适用于毕业设计、校园网络规划、企业网络规划等场合………………………

  • pytest的使用_pytest测试框架从入门到精通

    pytest的使用_pytest测试框架从入门到精通Pytest执行用例规则Pytest在命令行中支持多种方式来运行和选择测试用例1.对某个目录下所有的用例pytest2.对模块中进行测试pytesttest_mod.py3.对文件夹进行

  • 软件测试_笔记(完整版)[通俗易懂]

    软件测试_笔记(完整版)[通俗易懂]软件测试复习(部分)概述程序+文档+数据=软件狭义的软件测试定义:为发现软件缺陷而执行程序或系统的过程广义的软件测试定义:人工或自动地运行或测定某系统的过程,目的在于检验它是否满足规定的需求或弄清预期结果和实际结果间的差别为什么要做软件测试发现软件缺陷功能错功能遗漏超出需求部分(画蛇添足)性能不符合要求软件质量高低:是否符合用户习惯、符合用户需求测试…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号