如何使用ViewModel和LiveData进行改造API调用 [英] How to make retrofit API call using ViewModel and LiveData

查看:344
本文介绍了如何使用ViewModel和LiveData进行改造API调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我第一次尝试实现MVVM体系结构,并且对进行API调用的正确方法有些困惑.

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.

当前,我只是想从IGDB API中进行一个简单的查询,并在日志中输出第一项的名称.

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.

我的活动设置如下:

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;
    }

现在的问题是因为这是一个API调用,mGameList的初始值将为null,直到call.enqueue返回一个值.这将导致

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>>() {

  1. 那么处理LiveData的正确方法是什么, 在进行API调用时?
  2. 我是否执行了Retrofit API调用 在正确的地方?
  1. So what is the correct way to handle the observation of a LiveData, while API call is being made?
  2. Did I perform the Retrofit API call in the right place?

推荐答案

您的代码中存在3个问题.

There are 3 problems in your code.

  1. 您必须创建一个MutableLiveData对象,因为在API调用之前响应为空,然后您的LiveData对象将通过IGDB响应以某种方式填充.
  1. You must create a MutableLiveData object because you have an empty response before API call then your LiveData object will be filled somehow through the IGDB response.

private MutableLiveData<List<Game>> mGameList = new MutableLiveData();
//...
public LiveData<List<Game>> getGameList() {
    return mGameList;
}

  1. 另一个错误是更改了mGameList的引用而不是设置其值,因此请尝试更改:
  1. Another mistake is changing the reference of mGameList instead of setting its value, So try to change:

Timber.d("Call response body not null");
mGameList = response.body();

mGameList.setValue(response.body());

  1. ViewModel类中调用Retrofit是为了避免关注点分离.最好创建一个存储库模块并通过界面获取您的响应.详细信息,请阅读此文章.
  1. Calling retrofit inside your 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.

存储库模块负责处理数据操作.他们 为应用程序的其余部分提供干净的API.他们知道从哪里得到 数据以及更新数据时API调用的内容.你可以 将它们视为不同数据源之间的中介(持久性 模型,Web服务,缓存等).

Repository modules are responsible for handling data operations. They provide a clean API to the rest of the app. They know where to get the data from and what API calls to make when data is updated. You can consider them as mediators between different data sources (persistent model, web service, cache, etc.).

这篇关于如何使用ViewModel和LiveData进行改造API调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆