Od pewnego czasu borykam się z tym problemem. W moim projekcie istnieje kilka działań, które obejmują ListView i niestandardowy adapter rozszerzający BaseAdapter. Implementują także interfejsy, które zwykle informują, że dane zostały zmienione.Wywołanie BaseAdaptera systemu Android notifyDataSetChanged() z metody wywołania zwrotnego wywołującego
Jednak, gdy wywołuję metodę notifyDataSetChanged() z metody listener/interface zaimplementowanej w mojej klasie, ListView nie jest aktualizowany i żadna z metod adaptera nie jest wywoływana (getCount(), getView()).
Wiem, że ma to coś wspólnego z faktem, z którego wywoływana jest funkcja notifyDataSetChanged(), mam na myśli który wątek, ale nie całkiem rozumiem i nie mogę znaleźć prostego wyjaśnienia tego zachowania.
Jako obejście tego problemu używam programu Handler, który wywołuje metodę okresowo iw tej metodzie sprawdzam, czy wartość boolean 'needsToBeUpdated' jest prawdziwa i wtedy wywoływana jest metoda notifyDataSetChanged(). To jest brzydkie i jestem pewien, że musi istnieć sposób, aby zrobić to asynchronicznie.
Każda pomoc zostanie doceniona.
Pseudo-kod, co mówię:
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();
}
EDIT: Oczywiście zajęło mi prawie nie ma czasu, aby znaleźć odpowiedź kiedyś pisał ten tutaj ...
Nienawidzę aby to zrobić, ale wkładam trochę więcej wysiłku w szukanie odpowiedzi i myślę, że znalazłem to dzięki: http://developer.android.com/resources/articles/painless-threading.html - i to: http://developer.android.com/reference/android/os/Handler.html
Rozwiązanie jest boleśnie proste. Nie można zmienić interfejsu użytkownika w żadnym innym wątku oprócz wątku głównego/interfejsu użytkownika. Dlatego wykonanie tego w metodach oddzwaniania nie działa. Jednak utworzenie programu obsługi w wątku interfejsu użytkownika (np. W metodzie onCreate()) łączy go z wątkiem interfejsu użytkownika i może być później używany do publikowania zdarzeń w tym wątku.
mListUpdateHandler = new Handler();
W takim przypadku wymagana jest wewnętrzna klasa implementująca interfejs Runnable w przypadku konieczności dostosowania interfejsu użytkownika.
class UpdateListRunnable implements Runnable {
@Override
public void run() {
Log.i(LOGTAG, "UpdateListRunnable");
FriendsActivity.this.updateLists();
}
}
Wreszcie w metodzie zwrotnej zamieścimy zdarzenia z zewnątrz klasy UpdateListRunnable do głównego wątku poprzez Handler:
@Override
public void entriesUpdated(Collection<String> entries) {
Log.i(LOGTAG, "entriesUpdated");
for (String entry : entries) {
Log.i(LOGTAG, "entry: " + entry);
}
mListUpdateHandler.post(new UpdateListRunnable());
}
Dzięki temu upadteLists() metoda jest prowadzony w wątku UI a wszystko działa jak urok.