2013-03-20 23 views
24

Pracuję nad małą listą rzeczy do zrobienia. Użyłem CursorLoader do zaktualizowania ToDolistview od dostawcy treści. Mam napisaną funkcję onNewItemAdded(), która jest wywoływana, gdy użytkownik wprowadza nowy element w widoku tekstowym i klika enter. Patrz poniżej:W jaki sposób CursorLoader automatycznie aktualizuje widok, nawet jeśli aplikacja jest nieaktywna?

Przeczytałem, CursorLoader automatycznie aktualizuje widok, gdy istnieje zmiana danych w db dostawcy treści. To znaczy, przypuszczam, że getLoaderManager().restartLoader(0, null, this) musi być wywoływany niejawnie, ilekroć nastąpi zmiana danych, prawda? Ale tak się nie dzieje. Ilekroć dodaję nowy element (element jest dodawany do bazy danych z onNewItemAdded, ale restartLoader nie jest jawnie wywoływany), wstrzymaj tę aktywność i wznów ją ponownie. Nie widzę żadnego niejawnego wywołania restartLoader (nawet jeśli zmieniono db), a widok listy również nie został zaktualizowany o nowy element dodany. Dlaczego? W jaki sposób CursorLoader automatycznie aktualizuje widok, nawet jeśli aplikacja nie jest aktywna ??? Pozdrowienia :)

EDYCJA: Mam również używany getContext().getContentResolver().notifyChange(insertedId, null) we wstawce mojego dostawcy treści.

Odpowiedz

68

Znalazłem odpowiedź na moje pytanie. Ogólnie CursorLoader nie wykrywa automatycznie zmian danych i nie ładuje ich do widoku. Musimy śledzić URI dla zmian. Można to zrobić przez następujących etapów:

  1. rejestrację obserwatora w zawartości rezolwerem pośrednictwem kursora za pomocą: (wykonane w metodzie kwerendy ContentProvider)
    cursor.setNotificationUri(getContext().getContentResolver(), uri);

  2. Teraz, kiedy nie ma żadnych zmian w URI dane bazowe wykorzystujące insert()/delete()/update(), powiadomimy ContentResolver o zmianie przy użyciu:

    getContext().getContentResolver().notifyChange(insertedId, null);

  3. ten jest odbierany przez obserwatora, zarejestrowaliśmy w kroku-1 i to nazywa się ContentResolver.query(), który inturn nazywa ContentProvider „s query() metodę powrotu świeżego kursor LoaderManager. LoaderManager dzwoni przekazując ten kursor wraz z CursorLoader, gdzie aktualizujemy widok (używając Adapter.swapCursor()) ze świeżymi danymi.

dla niestandardowych AsyncTaskLoaders:

Czasami musimy nasz zwyczaj ładowarka zamiast CursorLoader. Tutaj możemy użyć innego obiektu niż kursor do wskazania załadowanych danych (takich jak lista itp.). W tym przypadku nie będziemy mieć wcześniejszego powiadomienia o ContentResolver za pomocą kursora. Aplikacja może również nie mieć dostawcy treści do śledzenia zmian URI. W tym scenariuszu korzystamy z BroadcastReceiver lub jawnego ContentObserver, aby osiągnąć automatyczne uaktualnienie widoku. Jest to następujące:

  1. Musimy zdefiniować nasz niestandardowy program ładujący, który rozszerza AsyncTaskLoader i wdraża wszystkie jego abstrakcyjne metody. W przeciwieństwie do CursorLoader nasz program ładujący niestandardowy może, ale nie musi korzystać z dostawcy treści, a jego konstruktor może nie zadzwonić pod numer ContentResolver.query(), gdy ten moduł ładujący zostanie uruchomiony. Dlatego używamy odbiornika do nadawania w tym celu.
  2. Należy utworzyć instancję klasy BroadCastReceiver lub ContentObserver w klasie OnStartLoading() abstrakcji AsyncTaskLoader.
  3. Ten odbiornik BroadCast powinien być zdefiniowany tak, aby odbierać transmisje zmieniające dane od dostawcy treści lub dowolnych zdarzeń systemowych (podobnie jak zainstalowana nowa aplikacja) i musi wywoływać metodę loadera o nazwie onContentChanged(), aby powiadomić program ładujący o zmianie danych. Program ładujący automatycznie wykona resztę w celu załadowania zaktualizowanych danych i wywoła numer onLoadFinished(), aby zaktualizować widok.

Aby uzyskać więcej informacji patrz poniżej: http://developer.android.com/reference/android/content/AsyncTaskLoader.html

Znalazłem to bardzo przydatne do jasnego wyjaśnienia: http://www.androiddesignpatterns.com/2012/08/implementing-loaders.html

3

Cóż, myślę, że można ponownie uruchomić program ładujący na pewne wydarzenia. Na przykład. w moim przypadku mam działalność TODO. Po kliknięciu opcji "dodaj" uruchamia nową aktywność, która ma wyświetlić nowe TODO.

Używam następujący kod aktywności macierzystej onActivityResult()

getLoaderManager().restartLoader(0, null, this); 

to działa dobrze dla mnie. Proszę podzielić się, jeśli istnieje lepsze podejście.

+0

Ten wydawał się być w porządku i najłatwiejszy, pracował dla mnie, ale czy istnieje lepszy sposób? – zeroDivider

2

uzyskać odniesienie do ładowacza podczas inicjalizacji następująco

Loader dayWeatherLoader = getLoaderManager().initLoader(LOADER_DAY_WEATHER, null, this); 

następnie utworzyć klasę, która rozciąga ContentObserver następująco

class DataObserver extends ContentObserver { 

    public DataObserver(Handler handler) { 
     super(handler); 
    } 

    @Override 
    public void onChange(boolean selfChange, Uri uri) { 
     dayWeatherLoader.forceLoad(); 
    } 
} 

Następnie zarejestrować treści obserwatora wewnątrz onResume metody cyklem następująco

@Override 
public void onResume() { 
    super.onResume(); 
    getContext().getContentResolver().registerContentObserver(CONTENTPROVIDERURI,true,new DayWeatherDataObserver(new Handler())); 
} 

Ilekroć nastąpi zmiana w d ata dostawcy treści, zostanie wywołana metoda onChange contentobserver, gdzie możesz poprosić program ładujący o ponowne załadowanie danych.