Как обновить LiveData из ViewModel из фоновой службы и обновить интерфейс
Недавно я изучаю архитектуру Android, которая недавно была представлена Google. Из документации я нашел это:
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
}
}
деятельность может получить доступ к этому списку следующим образом:
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
});
}
}
Мой вопрос, я собираюсь сделать это:
-
в функции loadUsers()
я асинхронно loadUsers()
данные, где сначала проверяю базу данных (Room) на эти данные
-
Если я не получу данные там, я сделаю вызов API для получения данных с веб-сервера.
-
Я вставлю извлеченные данные в базу данных (Комната) и обновлю интерфейс в соответствии с данными.
Каков рекомендуемый подход для этого?
Если я запускаю Service
для вызова API из loadUsers()
, как я могу обновить переменную MutableLiveData<List<User>> users
из этой Service
?
Ответы
Ответ 1
Я предполагаю, что вы используете компоненты архитектуры Android. На самом деле это не имеет значения, где бы вы ни service, asynctask or handler
для обновления данных. Вы можете вставить данные из сервиса или из асинхронной задачи, используя postValue(..)
. Ваш класс будет выглядеть так:
private void loadUsers() {
// do async operation to fetch users and use postValue() method
users.postValue(listOfData)
}
Поскольку users
являются LiveData
, база данных Room
отвечает за предоставление данных пользователям, где бы они ни были вставлены.
Note:
В архитектуре, аналогичной MVVM, хранилище в основном отвечает за проверку и извлечение локальных и удаленных данных.
Ответ 2
Пожалуйста, используйте текущие данные метод postValue (..) из фонового потока.
private void loadUsers() {
// do async operation to fetch users and use postValue() method
users.postValue(listOfData)
}
Ответ 3
... в функции loadUsers() Я получаю данные асинхронно... Если я запускаю службу для вызова API из метода loadUsers(), как Могу ли я обновить переменную MutableLiveData > users Сервис
Если приложение извлекает данные пользователя в фоновом потоке, postValue (а не setValue).
В методе loadData имеется ссылка на объект "пользователи" MutableLiveData. Метод loadData также извлекает некоторые свежие пользовательские данные откуда-то (например, репозиторий).
Теперь, если выполнение выполняется в фоновом потоке, MutableLiveData.postValue() обновляет внешние наблюдатели объекта MutableLiveData.
Возможно, что-то вроде этого:
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);
}
});
}
Ответ 4
Взгляните на руководство по архитектуре Android, которое сопровождает новые модули архитектуры, такие как LiveData
и ViewModel
. Они подробно обсуждают этот точный вопрос.
В своих примерах они не помещают его в службу. Посмотрите, как они решаются с помощью модуля "Репозиторий" и "Дооснастка". В добавлениях внизу представлены более полные примеры, включая состояние сети, сообщения об ошибках и т.д.
Ответ 5
https://developer.android.com/topic/libraries/architecture/guide.html
Имеет очень хорошие ответы на вашу проблему. Прокрутите весь путь до конца, чтобы увидеть, как вы можете сохранить ответ в вашей базе данных и обновить пользовательский интерфейс с помощью LiveData.
![enter image description here]()
Ответ 6
Если вы называете свой API в репозитории, то
В репозитории:
public MutableLiveData<LoginResponseModel> checkLogin(LoginRequestModel loginRequestModel) {
final MutableLiveData<LoginResponseModel> data = new MutableLiveData<>();
apiService.checkLogin(loginRequestModel)
.enqueue(new Callback<LoginResponseModel>() {
@Override
public void onResponse(@NonNull Call<LoginResponseModel> call, @Nullable Response<LoginResponseModel> response) {
if (response != null && response.isSuccessful()) {
data.postValue(response.body());
Log.i("Response ", response.body().getMessage());
}
}
@Override
public void onFailure(@NonNull Call<LoginResponseModel> call, Throwable t) {
data.postValue(null);
}
});
return data;
}
В ViewModel
public LiveData<LoginResponseModel> getUser() {
loginResponseModelMutableLiveData = repository.checkLogin(loginRequestModel);
return loginResponseModelMutableLiveData;
}
В Деятельности/Фрагмент
loginViewModel.getUser().observe(LoginActivity.this, loginResponseModel -> {
if (loginResponseModel != null) {
Toast.makeText(LoginActivity.this, loginResponseModel.getUser().getType(), Toast.LENGTH_SHORT).show();
}
});
Примечание: используя лямбду JAVA_1.8, вы можете использовать ее без