2012-03-06 13 views
5

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.

Odpowiedz

Powiązane problemy