Содержимое адаптера изменилось, но ListView не получил уведомления, в фоновом режиме ничего не обновлялось.

Я много читал об этом на SO, но мне не удалось найти решение в моем случае. Вот установка:

Действие A содержит список и отображаемые данные. Когда асинхронная задача моего диспетчера данных завершает обновление, происходит следующее:

protected void onPostExecute(Void v) {
        super.onPostExecute(v);

        if (editedDataSectionRows == null)
            editedDataSectionRows = new int[] {0, 0, 0, 0, 0, 0, 0};

        mData= editedData;
        mSectionRows = editedDataSectionRows;

        if (mCallback != null) {
            mCallback.dataUpdated();
        }
    }

Когда данные обновляются, действие A получает обратный вызов и выполняет следующие действия:

@Override
public void dataUpdated() {
    mData = mDataManagerInstance.getData();
    mDataSectionCount = mDataManagerInstance.getDataSectionRows();
    mListAdapter.notifyDataSetChanged();
}

mData - это ArrayList, содержащий все «строки», а mDataSectionCount - это int [], содержащий информацию о том, как mData следует разделить на разделы.

Теперь у Activity A есть меню параметров, которое может открыть второе Activity. Деятельность Б.

Время от времени, когда запускается Monkey и действие B завершается. Мой onResume для Activity A вызывается:

@Override
protected void onResume() {
    super.onResume();
    mDataManagerInstance = DataManager.getInstance();

    mDataManagerInstance.setDataUpdatedListener(this);
    mDataManagerInstance.updateData();

    this.invalidateOptionsMenu();
}

(updateData просто запускает мою AsyncTask, если она еще не запущена) И тогда дерьмо поражает вентилятор ...:

FATAL EXCEPTION: main
java.lang.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. [in ListView(-1, class com.applidium.headerlistview.HeaderListView$InternalListView) with Adapter(class se.*.android.activities.ListActivity$1)]
        at android.widget.ListView.layoutChildren(ListView.java:1582)
        at android.widget.ListView.commonKey(ListView.java:2104)
        at android.widget.ListView.onKeyDown(ListView.java:2085)
        at android.view.KeyEvent.dispatch(KeyEvent.java:2620)
        at android.view.View.dispatchKeyEvent(View.java:7149)
        at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1458)
        at android.widget.ListView.dispatchKeyEvent(ListView.java:2070)
        at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1462)
        at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1462)
        at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1462)
        at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1462)
        at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1462)
        at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1462)
        at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1898)
        at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1375)
        at android.app.Activity.dispatchKeyEvent(Activity.java:2356)
        at com.actionbarsherlock.app.SherlockFragmentActivity.dispatchKeyEvent(SherlockFragmentActivity.java:122)
        at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1825)
        at android.view.ViewRootImpl.deliverKeyEventPostIme(ViewRootImpl.java:3585)
        at android.view.ViewRootImpl.handleImeFinishedEvent(ViewRootImpl.java:3555)
        at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:2805)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:213)
        at android.app.ActivityThread.main(ActivityThread.java:4787)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:556)
        at dalvik.system.NativeStart.main(Native Method)

Любые идеи?


person Magnus Söderlund    schedule 15.05.2014    source источник


Ответы (1)


попробуйте сделать это в потоке пользовательского интерфейса

runOnUiThread(new Runnable(){
        public void run() {
            mListAdapter.notifyDataSetChanged();
        }
    });
person thealeksandr    schedule 15.05.2014
comment
Но onPostExecute уже должен запускаться в UI-потоке, верно? (Однако я добавлю это и тоже проверю, решит ли это мои проблемы.) - person Magnus Söderlund; 15.05.2014
comment
Только что проверил, без изменений. Я все еще получаю то же исключение, когда действие B закрывается и вызывается onResume - person Magnus Söderlund; 15.05.2014
comment
Ага, это странно. Вы проверили, что новые данные действительны? - person thealeksandr; 15.05.2014
comment
Да вроде нормально. Странно то, что это происходит только при возврате из Activity B, который был запущен A, и никогда, в первую очередь, при входе в Activity A ... - person Magnus Söderlund; 15.05.2014
comment
Я что-то красное. Вы уверены, что не меняете адаптер в потоке пользовательского интерфейса в другом месте и всегда должны вызывать notifyDataSetChanged () при изменении данных - person thealeksandr; 15.05.2014
comment
Да, я несколько раз проверял свой код. Есть одно место, где данные изменяются, и оттуда действие получает обратный вызов, чтобы оно могло собирать сами данные и сообщать адаптеру notifyDataSetChanged. Таким образом, данные адаптеров никогда не меняются, пока это не произойдет. - person Magnus Söderlund; 16.05.2014