The content of the adapter has changed but ListView did not receive

4757 ワード

主な原因はリストデータが変化したがadapterにnotifyに行くように通知しなかったことです
バグを修正する過程で、バグが表示されます.中の異常ログはjavaです.lang.IllegalStateException:The content of the adapter has changed but ListView did not receive anotification. Make sure the content of your adapter is not modified from abackground thread, but only from the UI thread. Make sure your adapter callsnotifyDataSetChanged() when its content changes. [in ListView(2131296454, classcom.android.contacts.widget.AutoScrollListView) with Adapter(classcom.android.contacts.group.GroupBrowseListAdapter)] atandroid.widget.ListView.layoutChildren(ListView.java:1555) atcom.android.contacts.widget.AutoScrollListView.layoutChildren(AutoScrollListView.java:74) atandroid.widget.ListView.setSelectionInt(ListView.java:1987) atandroid.widget.AbsListView.resurrectSelection(AbsListView.java:5512) atandroid.widget.AbsListView.onWindowFocusChanged(AbsListView.java:2858) atandroid.view.View.dispatchWindowFocusChanged(View.java:7900) atandroid.view.ViewGroup.dispatchWindowFocusChanged(ViewGroup.java:968) atandroid.view.ViewGroup.dispatchWindowFocusChanged(ViewGroup.java:972) atandroid.view.ViewGroup.dispatchWindowFocusChanged(ViewGroup.java:972) at android.view.ViewGroup.dispatchWindowFocusChanged(ViewGroup.java:972) atandroid.view.ViewGroup.dispatchWindowFocusChanged(ViewGroup.java:972) atandroid.view.ViewGroup.dispatchWindowFocusChanged(ViewGroup.java:972) atandroid.view.ViewGroup.dispatchWindowFocusChanged(ViewGroup.java:972) atandroid.view.ViewGroup.dispatchWindowFocusChanged(ViewGroup.java:972) atandroid.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:3149) atandroid.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:136) atandroid.app.ActivityThread.main(ActivityThread.java:5120) atjava.lang.reflect.Method.invokeNative(Native Method) atjava.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:818) atcom.android.internal.os.ZygoteInit.main(ZygoteInit.java:634) atdalvik.system.NativeStart.main(Native Method)
簡単に見るとIllegalStateExceptionで、ListView 1555行から投げ出されています.
// Handle the empty set by removing all views that are visible

// and calling it a day

if (mItemCount == 0) {

      resetList();

      invokeOnItemScrollListener();

      return;

 } 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!=mAdapter.getCount()の時にこの異常を投げ出します.では二つの問題を考えてみましょう
1.mItemCountはいつ付与されますか?
2. mAdapter.getCount()とは何でしょうか.
まず第2点を分析します.getCount()は、比較的簡単なので、皆さんもよく知っています.そうですね.Adapterをカスタマイズするときに、getCount()を書き換える方法です.
このような書き方に似ている
public class GroupBrowseListAdapter extends BaseAdapter {

         ...

         Private List<String> mdata;

         public int getCount() {

        return mdata.size();

}

...

}
一般的には、集合(list,cursor,配列)のようなサイズを表示します.つまり、listviewのItemの合計数です.
では、第1点を分析すると、mItemCountはどのような賦値をしているのでしょうか.
まず、定義された場所を見つけます.
ファイルのパス:
frameworks\base\core\java\android\widget\AdapterView.java
コード:
/**

     * The number of items in the current adapter.

     */

@ViewDebug.ExportedProperty(category = "list")

int mItemCount;
賦課された場所
1.        ListView.setAdapter
public void setAdapter(ListAdapter adapter) {

...

if (mAdapter != null) {

mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();

mOldItemCount = mItemCount;

mItemCount = mAdapter.getCount();

...

}

...

}
2.        frameworks\base\core\java\android\widget\AdapterView.java
class AdapterDataSetObserver extends DataSetObserver {

private Parcelable mInstanceState = null;

<a href="http://home.51cto.com/index.php?s=/space/5017954" target="_blank">@Override</a>

public void onChanged() {

mDataChanged = true;

mOldItemCount = mItemCount;

mItemCount = getAdapter().getCount();

....

}
上はmItemCountに付与された2つの場所です
1つ目はListViewにadapterを設定とき、2つ目はadapterを呼び出す.
notifyDataSetChanged()のときに呼び出す
では、この問題を解決するのは簡単です.あなたのデータセットが変化したとき(このときgetCount()の戻り値が変化します)、adapterを呼び出します.notifyDataSetChanged()は、adapterにmItemCountを更新するように通知します.