16

Niedawno omawiam architekturę Androida, która została niedawno wprowadzona przez google. Z Documentation Znalazłem to:Jak zaktualizować LiveData obiektu ViewModel z usługi w tle i Aktualizuj interfejs użytkownika

public class MyViewModel extends ViewModel { 
    private MutableLiveData<List<User>> users; 
    public LiveData<List<User>> getUsers() { 
     if (users == null) { 
      users = new MutableLiveData<List<Users>>(); 
      loadUsers(); 
     } 
     return users; 
    } 

    private void loadUsers() { 
     // do async operation to fetch users 
    } 
} 

działalność może uzyskać dostęp do tej listy, co następuje:

public class MyActivity extends AppCompatActivity { 
    public void onCreate(Bundle savedInstanceState) { 
     MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class); 
     model.getUsers().observe(this, users -> { 
      // update UI 
     }); 
    } 
} 

Moje pytanie brzmi, w funkcji loadUsers() ja ściągam dane asynchronicznie, gdzie najpierw sprawdzi baza danych (pokój) dla tych danych, jeśli nie dostanę tam danych, wykonam wywołanie API, aby pobrać dane z serwera WWW. Następnie wstawię pobrane dane do bazy danych (Room) i zaktualizuję interfejs użytkownika zgodnie z danymi. Jakie jest zalecane podejście do tego?

jeśli rozpocznę Service zadzwonić API z metody loadUsers(), w jaki sposób mogę zaktualizować MutableLiveData<List<User>> users zmienną z tego Service?

+2

Przede wszystkim brakuje repozytorium. Twój ViewModel nie powinien wykonywać żadnych zadań ładowania danych. Poza tym, ponieważ używasz pokoju, Twoja usługa nie musi aktualizować LiveData bezpośrednio w ViewModel. Serwis może jedynie wstawiać dane do pokoju, a dane ViewModelData powinny być dołączane tylko do pokoju, a także otrzymywać aktualizacje z pokoju (po wstawieniu danych usługi). Ale dla absolutnie najlepszej architektury spójrz na implementację klasy NetworkBoundResource od dołu tej strony: https://developer.android.com/topic/libraries/architecture/guide.html –

+0

dziękuję za sugestię :) – CodeCameo

+0

Klasa repozytoriów nie jest wspomniany w dokumentach opisujących POKÓJ lub elementy architektury Androida – jonney

Odpowiedz

3

Zakładam, że używasz android architecture components. W rzeczywistości nie ma znaczenia, gdzie wywołujesz service, asynctask or handler, aby zaktualizować dane. Możesz wstawić dane z usługi lub asynktaksu. Twoja klasa będzie wyglądać this-

public LiveData<List<User>> getUsers() { 
     if (users == null) { 
      users = new MutableLiveData<List<Users>>(); 
      // Asynchronous call for inserting data using service or asynctask. 
      loadUsers(); 
     } 
     // Dao live data will provide you all users information if data inserted. 
     LiveData<List<User>> mUsers = mDb.userDao().getAllUsers(); 
     users.postValue(mUsers); 
     return users; 
    } 

Jako getAllUsers() jest LiveData, Room baza danych jest odpowiedzialny za dostarczanie danych użytkowników, gdziekolwiek jest ona włożona.

Note: W architekturze podobnej do MVVM repozytorium jest głównie odpowiedzialne za sprawdzanie i pobieranie lokalnych danych i danych zdalnych.

+0

Otrzymuję komunikat "java.lang.IllegalStateException: Nie mogę uzyskać dostępu do bazy danych w głównym wątku, ponieważ" na wywoływanie moich metod db jak powyżej, Czy możesz powiedzieć, co może być nie tak ? – pcj

+0

Używam evernote-job, która aktualizuje bazę danych w tle, gdy jestem w interfejsie użytkownika. Ale 'LiveData' nie aktualizuje –

2

Spójrz na Android architecture guide, który towarzyszy nowym modułom architektury, takim jak LiveData i ViewModel. Dokładnie omawiają ten dokładny problem.

W swoich przykładach nie umieszczają go w serwisie. Sprawdź, jak rozwiązują ten problem, korzystając z modułu "repozytorium" i opcji Retrofit. Te dodatki na dole to bardziej kompletne przykłady w tym komunikacji stan sieci, raportowanie błędów, itp

5

... W loadUsers() funkcję jestem pobierania danych asynchronicznie ... Jeśli zacznę serwis, który zadzwoń do API z metody loadUsers(), w jaki sposób mogę zaktualizować zmienną użytkowników MutableLiveData> z tej usługi ?

Jeśli aplikacja jest pobieranie danych użytkownika w wątku tła, postValue (zamiast setValue) będzie użyteczna.

W metodzie loadData znajduje się odwołanie do obiektu użytkowników "MutableLiveData". Metoda loadData pobiera również gdzieś nowe dane użytkownika (na przykład repozytorium).

Teraz, jeśli wykonanie jest w wątku tła, MutableLiveData.postValue() aktualizuje się poza obserwatorami obiektu MutableLiveData.

Może coś takiego:

private MutableLiveData<List<User>> users; 

. 
. 
. 

private void loadUsers() { 
    // do async operation to fetch users 
    ExecutorService service = Executors.newSingleThreadExecutor(); 
    service.submit(new Runnable() { 
     @Override 
     public void run() { 
      // on background thread, obtain a fresh list of users 
      List<String> freshUserList = aRepositorySomewhere.getUsers(); 

      // now that you have the fresh user data in freshUserList, 
      // make it available to outside observers of the "users" 
      // MutableLiveData object 
      users.postValue(freshUserList);   
     } 
    }); 

} 
+0

Metoda' getUsers() 'repozytorium może wywoływać api dla danych, które są asynchroniczne (może uruchomić usługę lub asynktask dla tego) w takim przypadku jak może zwrócić List z jego instrukcji return? – CodeCameo

+0

Być może może to potrwać obiekt LiveData jako argument. (Coś jak reository.getUsers (użytkownicy)). Następnie metoda repozytorium wywołałaby samą users.postValue. W takim przypadku metoda loadUsers nie potrzebuje nawet wątku tła. –

20

Proszę używać żywo Danych postValue (..) metoda z wątku tła.

private void loadUsers() { 
    // do async operation to fetch users and use postValue() method 
    users.postValue(listOfData) 
} 
+2

Przypominamy, że funkcja postValue() jest chroniona w LiveData, ale publicznie w MutableLiveData –

Powiązane problemy