这是我第一次尝试实现MVVM体系结构,并且对进行API调用的正确方法有些困惑。
当前,我只是想从IGDB API中进行一个简单的查询,并在日志中输出第一项的名称。
我的活动设置如下:
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>>() {
答案 0 :(得分:12)
您的代码中存在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
类中调用改造是为了避免关注点分离。最好创建一个存储库模块并通过界面获取您的响应。阅读此article了解详情。存储库模块负责处理数据操作。他们 为应用程序的其余部分提供干净的API。他们知道从哪里得到 数据以及更新数据时API调用的内容。您可以 将它们视为不同数据源之间的中介(永久 模型,Web服务,缓存等)。
答案 1 :(得分:0)
我只是受到Google演示的启发,并创建了一个库,可以为Livefit添加LiveData支持。用法很简单:
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