Вызов BaseAdapter Android notifyDataSetChanged () из метода обратного вызова слушателя - PullRequest
5 голосов
/ 07 марта 2012

Я уже давно борюсь с этим.В моем проекте есть несколько Activity, которые включают ListView и пользовательский адаптер, расширяющий BaseAdapter.Они также реализуют некоторые интерфейсы, которые обычно сообщают ему, что данные были изменены.

Однако, когда я вызываю notifyDataSetChanged () из метода слушателя / интерфейса, реализованного в моем классе, ListView не обновляется, и ни один изметоды адаптера называются (getCount (), getView ()).

Я знаю, что это как-то связано с тем фактом, что вызывается notifyDataSetChanged (), я имею в виду, какой поток, но я неЯ полностью понимаю это и не могу найти прямое объяснение этого поведения.

В качестве обходного пути этой проблемы я использую обработчик, который периодически вызывает метод, и в этом методе я смотрю, является ли логическое значение needsToBeUpdated равнымистина, и тогда я вызываю метод notifyDataSetChanged ().Это уродливо, хотя, и я уверен, что должен быть способ сделать это асинхронно.

Любая помощь будет оценена.

Псевдокод того, о чем я говорю:

public class FriendsActivity extends Activity implements FriendsListener {
private ListView mListView;
private ArrayList<Friends> mFriendsList;
private FriendsAdapter mFriendsAdapter;
private boolean mNeedsToBeUpdated;
private Handler mListUpdateHandler;
private Runnable mListUpdateTask;

onCreate() {
    initViews();
    mFriendsAdapter = new FriendsAdapter(mFriendsList);
    mListView.setAdapter(mFriendsAdapter);
    SomeStaticClass.addFriendListener(this)

    mNeedsToBeUpdated = false;

    mListUpdateHandler = new Handler();
    mListUpdateHandler.removeCallbacks(mListUpdateTask);
    mListUpdateHandler.postDelayed(mListUpdateTask, 10000);

}

onListenerMethod() {
    updateFriendsList();
    mFriendsAdapter.updateDataSource(mFriendsList);
    mFriendsAdapter.notifyDataSetChanged(); // THIS DOESN'T UPDATE THE VIEWS
    mNeedsToBeUpdated = true;
}

protected void onResume() {
    mListUpdateTask = new Runnable() {
        public void run() {
            if (mNeedsToBeUpdated ) {
                updateFriendsList();
                mFriendsAdapter.updateDataSource(mFriendsList);
                mFriendsAdapter.notifyDataSetChanged(); // THIS UPDATES THE VIEWS
                mListsRequireUpdating = false;
            }
            mListUpdateHandler.postDelayed(mListUpdateTask, 10000);
        }
    };
    mListUpdateHandler = new Handler();
    mListUpdateHandler.removeCallbacks(mListUpdateTask);
    mListUpdateHandler.post(mListUpdateTask);
    super.onResume();
}

РЕДАКТИРОВАТЬ: Конечно, у меня почти не было времени, чтобы найти ответ, как только я разместил это здесь ...

Я ненавижу это делать, но я приложил больше усилий для поисказа ответ, и я думаю, что нашел его благодаря этому: http://developer.android.com/resources/articles/painless-threading.html - и это: http://developer.android.com/reference/android/os/Handler.html

Решение до боли простое.Невозможно изменить пользовательский интерфейс в каком-либо другом потоке, кроме основного / пользовательского потока.Вот почему выполнение этого в методах обратного вызова не работает.Однако создание обработчика в потоке пользовательского интерфейса (например, в методе onCreate ()) связывает его с потоком пользовательского интерфейса и может позже использоваться для публикации событий в этом потоке.

mListUpdateHandler = new Handler();

Затем внутренний классреализация интерфейса Runnable необходима там, где выполняется настройка пользовательского интерфейса.

class UpdateListRunnable implements Runnable {
        @Override
        public void run() {
            Log.i(LOGTAG, "UpdateListRunnable");
            FriendsActivity.this.updateLists();            
        }
    }

Наконец, в методе обратного вызова мы публикуем событие с классом UpdateListRunnable в основном потоке через обработчик:

@Override
    public void entriesUpdated(Collection<String> entries) {
        Log.i(LOGTAG, "entriesUpdated");
        for (String entry : entries) {
            Log.i(LOGTAG, "entry: " + entry);
        }
        mListUpdateHandler.post(new UpdateListRunnable());
    }

Благодаря этому метод upadteLists () запускается в потоке пользовательского интерфейса, и все работает как чудо.

1 Ответ

0 голосов
/ 11 июля 2012

У меня была такая же проблема с моим приложением.Первым решением было использование обработчиков.Более элегантным является использование Loaders - отметьте http://developer.android.com/guide/components/loaders.html! Пакет совместимости для более старых версий Android делает их доступными для Android 1.6 +

...