如何使用 ViewModel 和 LiveData 进行改造 API 调用

新手上路,请多包涵

这是我第一次尝试实现 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 的初始值将为空,直到 call.enqueue 返回一个值。这将导致空指针异常

popViewModel.getGameList().observe(this, new Observer<List<Game>>() {

  1. 那么在进行 API 调用时处理 LiveData 观察的正确方法是什么?
  2. 我是否在正确的位置执行了 Retrofit API 调用?

原文由 Chao Li 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 425
2 个回答

您的代码中有 3 个问题。

  1. 您必须创建一个 MutableLiveData 对象,因为在 API 调用之前您的响应为空,然后您的 LiveData 对象将通过 IGDB 响应以某种方式填充。
 private MutableLiveData<List<Game>> mGameList = new MutableLiveData();
//...
public LiveData<List<Game>> getGameList() {
    return mGameList;
}

  1. 另一个错误是更改了 mGameList 的引用而不是设置它的值,因此尝试更改:
 Timber.d("Call response body not null");
mGameList = response.body();

mGameList.setValue(response.body());

  1. 在你的 ViewModel 类中调用改造避免了关注点分离。最好创建一个存储库模块并通过接口获取您的响应。阅读这篇 文章 了解详情。

存储库模块负责处理数据操作。他们为应用程序的其余部分提供了一个干净的 API。他们知道从哪里获取数据以及在更新数据时调用哪些 API。您可以将它们视为不同数据源(持久模型、Web 服务、缓存等)之间的中介。

原文由 Saeed Masoumi 发布,翻译遵循 CC BY-SA 4.0 许可协议

刚刚受Google的Demo启发,创建了一个库,可以为Retrofit添加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

原文由 shawnlinboy 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题