java - Android MVVM 架构和观察来自 API 的数据变化
问题描述
我是 Android MVVM 架构的新手。我有一个在本地运行的 API,其中包含数据(“交易”)。我想简单地向 API 发出请求并在文本字段中显示该数据。目前,首次加载片段时数据不会显示,但如果我转到另一个活动然后返回它加载的片段。
这里有 3 类重要性。
仪表板视图模型.java:
package com.example.android_client.ui.dashboard;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.example.android_client.models.Deal;
import com.example.android_client.repository.Repository;
import java.util.List;
public class DashboardViewModel extends ViewModel {
private MutableLiveData<String> mText;
private Repository repository;
private MutableLiveData<List<Deal>> deals = null;
public void init() {
if(this.deals == null) {
this.repository = Repository.getInstance();
this.deals = this.repository.getDeals();
}
}
public DashboardViewModel() {
this.mText = new MutableLiveData<>();
}
public LiveData<List<Deal>> getDeals() {
return this.deals;
}
}
仪表板片段.java:
package com.example.android_client.ui.dashboard;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import com.example.android_client.R;
import com.example.android_client.models.Deal;
import java.util.List;
public class DashboardFragment extends Fragment {
private DashboardViewModel dashboardViewModel;
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_dashboard, container, false);
final TextView textView = root.findViewById(R.id.text_dashboard);
dashboardViewModel = ViewModelProviders.of(this).get(DashboardViewModel.class);
dashboardViewModel.init();
dashboardViewModel.getDeals().observe(this, new Observer<List<Deal>>() {
@Override
public void onChanged(List<Deal> deals) {
if (deals != null && !deals.isEmpty()) {
System.out.println(deals.get(0).toString());
textView.setText(deals.get(0).toString());
}
}
});
return root;
}
}
和 Repository.java:
package com.example.android_client.repository;
import androidx.lifecycle.MutableLiveData;
import com.example.android_client.models.Deal;
import com.google.gson.Gson;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
public class Repository {
private static Repository instance;
private ArrayList<Deal> dealsList = new ArrayList<>();
private final OkHttpClient client = new OkHttpClient();
public static Repository getInstance() {
if(instance == null) {
instance = new Repository();
}
return instance;
}
private Repository() {}
public MutableLiveData<List<Deal>> getDeals() {
setDeals();
MutableLiveData<List<Deal>> deals = new MutableLiveData<>();
deals.setValue(dealsList);
return deals;
}
private void setDeals() {
Request request = new Request.Builder()
.url("http://10.0.2.2:8000/api/deals?<params here>")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
try (ResponseBody responseBody = response.body()) {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
String jsonDeals = responseBody.string(); // can only call string() once or you'll get an IllegalStateException
Deal[] deals = new Gson().fromJson(jsonDeals, Deal[].class);
dealsList = new ArrayList<>(Arrays.asList(deals));
}
}
});
}
}
单步执行 Repository 类中的代码时,我可以看到setDeals()
加载片段时调用了该代码,并且回调中的请求已排队。第一次getDeals()
返回时,它返回一个包含 0 个交易的列表(在MutableLiveData
对象内)。
onResponse
在片段已经加载之前,回调不会运行。调试时,我可以看到数据在对象中(所有 Gson 东西都可以正常工作),但onChanged
不会再次被调用(设置文本视图)。
我没有观察到deals
正确的变化吗?
解决方案
我认为这会有所帮助。在网络调用的 onResponse 中尝试 MutableLiveData 上的 postValue。请更改您的存储库类,如下所示:
package com.example.android_client.repository;
import androidx.lifecycle.MutableLiveData;
import com.example.android_client.models.Deal;
import com.google.gson.Gson;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
public class Repository {
private static Repository instance;
private ArrayList<Deal> dealsList = new ArrayList<>();
private final OkHttpClient client = new OkHttpClient();
MutableLiveData<List<Deal>> deals = new MutableLiveData<>();
public static Repository getInstance() {
if(instance == null) {
instance = new Repository();
}
return instance;
}
private Repository() {}
private MutableLiveData<List<Deal>> getDeals() {
Request request = new Request.Builder()
.url("http://10.0.2.2:8000/api/deals?<params here>")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
try (ResponseBody responseBody = response.body()) {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
String jsonDeals = responseBody.string(); // can only call string() once or you'll get an IllegalStateException
Deal[] deals = new Gson().fromJson(jsonDeals, Deal[].class);
dealsList = new ArrayList<>(Arrays.asList(deals));
deals.postValue(dealsList);
}
}
});
return deals;
}
}
推荐阅读
- javascript - 将网页保存为带有 rvest 的 HTML 文件?
- perl - Perl:无条件的文件测试运算符
- windows - Windows 上的 CMake 生成要构建为 SHARED 的库集的静态和动态版本
- gulp - 并行任务和系列中的 Gulp 汇总
- r - 使用定义的函数时出错 - 剪切错误。“breaks”和“labels”的默认长度不同
- selenium-extent-report - 在 Selenium 的范围报告中使用方法“loadXMLConfig”和“attachReporter”时出错
- java - 为什么 Spring mail 无法识别我的 Gmail 帐户?
- amazon-ses - 为什么我收到 MessageRejected 错误?
- javascript - Discord.js,通过数组中的 ID 查找用户是否具有角色
- javascript - 使用数组元素进行 JavaScript 解构