Recently, I found a bug RELATED TO THE listview adapter. The FC is generated, and the descriptive information is about
"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)]"
It means that the data in the adapter has changed, but the UI has not been updated. Have you forgotten to call yydatasetchanged?
This is actually very misleading information. Under normal circumstances, we will not forget to call this function. However, if we accidentally inherit a new class from listview and override its getadapter method, a problem may occur.
Listview supports headerview and footerview, that is, add? Some special views. Its implementation method is through a headerviewlistadapter.
Headerviewlistadapter encapsulates an adapter, which is set by the user. The corresponding code in listview is
@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; }
The getadapter of listview returns madapter, which can be a headerviewlistadapter.
If override getadapter and the headerviewlistadapter is returned, a problem occurs. That is, the FC mentioned above.
How does this problem occur?
First, the exception is thrown in the layoutchildren function. The condition is mitemcount! = Madapter. getcount (). The Code is as follows:
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() + ")]"); }
So where is the value of mitemcount assigned? Mitemcount is not a member of listview, but a member of listview's super class: adapterview. This value is also set in dataobserver. onchanged. You can refer to the source code of adapterview:
Class adapterdatasetobserver extends datasetobserver {private parcelable minstancestate = NULL; @ override public void onchanged () {mdatachanged = true; molditemcount = mitemcount; mitemcount = getadapter (). getcount (); // here! Note the usage method getadapter () // detect the case where a cursor that was previusly 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 ();}
Suppose getadapter ()! = Madapter: getadatper returns madapter (headerlistviewadapter. getcount () = getadapter (). getcount () + header view count + footer view count.
The above problems are inevitable.