Я уже давно борюсь с этим.В моем проекте есть несколько 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 () запускается в потоке пользовательского интерфейса, и все работает как чудо.