this is the first time I'm trying to implement MVVM architecture, and I'm a bit confused about the correct way to make an API call.
Currently, I'm just trying to make a simple query from the IGDB API, and output the name of the first item in a log.
My activity is setup as follow:
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);
}
});
}
}
My View Model is set up as follow:
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;
}
Now the problem is because this is an API call, the initial value of mGameList
will be null, until call.enqueue
returns with a value. This will cause a null pointer exception with
popViewModel.getGameList().observe(this, new Observer<List<Game>>() {
- So what is the correct way to handle the observation of a LiveData, while API call is being made?
- Did I perform the Retrofit API call in the right place?
There are 3 problems in your code.
MutableLiveData
object because you have an empty response before API call then yourLiveData
object will be filled somehow through the IGDB response.mGameList
instead of setting its value, So try to change:to
ViewModel
class is avoiding separation of concerns. It's better to create a repository module and get your response through an interface. Read this article for details.