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)


相关推荐

  • 利用serv-u创建ftp服务器_ftp读取目录列表失败

    利用serv-u创建ftp服务器_ftp读取目录列表失败一、由来最近改写了项目中ftp上传部分的代码。用到的组件为:<dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId><version>3.3</version></depen…

  • 抖音设备激活破解方法

    抖音设备激活破解方法,https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

  • 《如何搭建小微企业风控模型》第三节 风控模型概览

    《如何搭建小微企业风控模型》第三节 风控模型概览《如何搭建小微企业风控模型》第三节风控模型概览

  • 卸载烦人的赛门铁克

    卸载烦人的赛门铁克问题:电脑上SymantecEndpointProtection无法进行卸载,在卸载的时候提示需要密码。解决:网上查过很多的解决方法,比如修改相关注册表,或者使用360粉碎文件,但都没有将SymantecEndpointProtection卸载掉,最后查到需要使用CleanWipe来卸载。网上找了很多CleanWipe版本,但是卸载都是版本过低,导致卸载不了。本人使用的Cl…

  • idea2021mac激活码[免费获取]「建议收藏」

    (idea2021mac激活码)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。https://javaforall.cn/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~MLZPB5EL5Q-eyJsaWNlbnNlSWQiOi…

  • NTP时间服务器

    1.NTP简介NTP(NetworkTimeProtocol网络时间协议)是一个用于同步计算机时钟的网络协议。它可以使计算机与其他服务器或时钟源进行时间同步,进行高精度的时间校正。简而言之,NTP就是使一台或多台服务器(客户端)与时间服务器(服务端)之间进行时间同步(即客户端与服务端的时间同步),以保证时间的统一性2.NTP服务器架设   上面提到客户端与服务端的时间

发表回复

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

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