Как сделать API-интерфейс для переоснащения с помощью ViewModel и LiveData
это первый раз, когда я пытаюсь реализовать MVVM-архитектуру, и я немного запутался в правильном способе создания вызова API.
В настоящее время я просто пытаюсь сделать простой запрос из API IGDB и вывести имя первого элемента в журнале.
Моя деятельность настраивается следующим образом:
public class PopularGamesActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_popular_games);
PopularGamesViewModel popViewModel = ViewModelProviders.of(this).get(PopularGamesViewModel.class);
popViewModel.getGameList().observe(this, new Observer<List<Game>>() {
@Override
public void onChanged(@Nullable List<Game> gameList) {
String firstName = gameList.get(0).getName();
Timber.d(firstName);
}
});
}
}
Моя модель просмотра настроена следующим образом:
public class PopularGamesViewModel extends AndroidViewModel {
private static final String igdbBaseUrl = "https://api-endpoint.igdb.com/";
private static final String FIELDS = "id,name,genres,cover,popularity";
private static final String ORDER = "popularity:desc";
private static final int LIMIT = 30;
private LiveData<List<Game>> mGameList;
public PopularGamesViewModel(@NonNull Application application) {
super(application);
// Create the retrofit builder
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(igdbBaseUrl)
.addConverterFactory(GsonConverterFactory.create());
// Build retrofit
Retrofit retrofit = builder.build();
// Create the retrofit client
RetrofitClient client = retrofit.create(RetrofitClient.class);
Call<LiveData<List<Game>>> call = client.getGame(FIELDS,
ORDER,
LIMIT);
call.enqueue(new Callback<LiveData<List<Game>>>() {
@Override
public void onResponse(Call<LiveData<List<Game>>> call, Response<LiveData<List<Game>>> response) {
if (response.body() != null) {
Timber.d("Call response body not null");
mGameList = response.body();
} else {
Timber.d("Call response body is null");
}
}
@Override
public void onFailure(Call<LiveData<List<Game>>> call, Throwable t) {
Timber.d("Retrofit call failed");
}
});
}
public LiveData<List<Game>> getGameList() {
return mGameList;
}
Теперь проблема в том, что это вызов API, начальное значение mGameList
будет равно null, пока call.enqueue
вернется со значением. Это приведет к исключению нулевого указателя с
popViewModel.getGameList().observe(this, new Observer<List<Game>>() {
- Итак, каков правильный способ обработки наблюдения LiveData, в то время как вызов API выполняется?
- Я выполнил вызов API Retrofit в нужном месте?
Ответы
Ответ 1
В вашем коде 3 проблемы.
- Вы должны создать объект
MutableLiveData
потому что у вас есть пустой ответ перед вызовом API, тогда ваш объект LiveData
будет каким-то образом заполнен через ответ IGDB.
private MutableLiveData<List<Game>> mGameList = new MutableLiveData();
//...
public LiveData<List<Game>> getGameList() {
return mGameList;
}
- Другая ошибка - изменение ссылки на
mGameList
вместо установки его значения, поэтому попробуйте изменить:
Timber.d("Call response body not null");
mGameList = response.body();
в
mGameList.setValue(response.body());
- Вызов модернизации внутри вашего класса
ViewModel
позволяет избежать разделения проблем. Лучше создать модуль репозитория и получить ответ через интерфейс. Прочитайте эту статью для деталей.
Модули репозитория отвечают за обработку данных. Они обеспечивают чистый API для остальной части приложения. Они знают, откуда взять данные и какие вызовы API следует выполнять при обновлении данных. Вы можете рассматривать их как посредников между различными источниками данных (постоянная модель, веб-служба, кэш и т.д.).
Ответ 2
Можете ли вы помочь мне, у меня та же проблема. Я работаю с компонентами арки? Спасибо!
Ответ 3
Я просто вдохновился Google Demo и создал библиотеку, в которую можно добавить поддержку LiveData для Retrofit. Использование простое:
Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(LiveDataCallAdapterFactory())
.build()
.create(GithubService::class.java)
.getUser("shawnlinboy").observe(this,
Observer { response ->
when (response) {
is ApiSuccessResponse -> {
//success response
}
else -> {
//failed response
}
}
})
Сайт библиотеки:https://github.com/shawnlinboy/retrofit-livedata-adapter