Override ListView getAdapter造成的後果

來源:互聯網
上載者:User

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.

出現上面的問題就在所難免了。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.