如何链接 MVVM 模式的改造和存储库/视图模型?



我在将 Retrofit 与 MVVM 架构联系起来时遇到问题。事实上,在阅读了他们只谈论用于SQLite本地数据库的房间的文档后,我搜索了相同的内容,但搜索了来自Rest Server的数据。 所以,我试图做类似的事情,但它不起作用: https://proandroiddev.com/mvvm-architecture-viewmodel-and-livedata-part-1-604f50cda1

我有一个观察视图模型的活动:

活动代码 :

mFlightPlanViewModel = ViewModelProviders.of(this).get(FlightPlanViewModel.class);
mFlightPlanViewModel.getFlightPlans().observe(this, (flightPlans) -> {
Log.d(TAG, "ON_CHANGED");
mFlightPlanAdapter.setFlightPlans(flightPlans);
});

视图模型 :

public class FlightPlanViewModel extends AndroidViewModel {
private static final String TAG = "FlightPlanViewModel";
private LiveData<List<FlightPlan>> mFlightPlans;
private FlightPlanRepository mFlightPlanRepository;
public FlightPlanViewModel(@NonNull Application application) {
super(application);
Log.d(TAG, "CONSTRUCTOR");
mFlightPlanRepository = FlightPlanRepository.getInstance();
mFlightPlans = mFlightPlanRepository.getFlightPlans();
}
public LiveData<List<FlightPlan>> getFlightPlans() {
Log.d(TAG, "GET_FLIGHT_PLANS");
return mFlightPlans;
}
}

视图模型回答使用单例模式的存储库:

public class FlightPlanRepository {
private static final String TAG = "FlightPlanRepository";
private static FlightPlanRepository instance;
private RestApi mRestApi;
private FlightPlanRepository() {
Log.d(TAG, "CONSTRUCTOR");
mRestApi = RestDao.getRestDao();
}
public static FlightPlanRepository getInstance() {
Log.d(TAG, "GET_INSTANCE");
if (instance == null) {
instance = new FlightPlanRepository();
}
return instance;
}
public MutableLiveData<List<FlightPlan>> getFlightPlans() {
Log.d(TAG, "GET_FLIGHT_PLANS");
final MutableLiveData<List<FlightPlan>> data = new MutableLiveData<>();
mRestApi.getFlightPlanList().enqueue(new Callback<List<FlightPlan>>() {
@Override
public void onResponse(Call<List<FlightPlan>> call, Response<List<FlightPlan>> response) {
if (response.code() == 200) {
List<FlightPlan> temp = response.body();
for (FlightPlan flightPlan : temp) {
Log.d(TAG + "res", flightPlan.toString());
}
data.setValue(response.body());
Log.d(TAG + "res", response.toString());
}
}
@Override
public void onFailure(Call<List<FlightPlan>> call, Throwable t) {
List<FlightPlan> flightPlans = new ArrayList<>();
flightPlans.add(new FlightPlan(0, "Test", 3.551, 50.52, 3.55122, 50.52625));
data.setValue(flightPlans);
Log.d(TAG, t.getMessage());
}
});
return data;
}
}

存储库使用改造实例:

public class RestDao {
private static final String BASE_URL = "http://192.168.1.78:8080";
private static Retrofit instance;
private static Retrofit getInstance() {
if (instance == null) {
instance = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return instance;
}
public static RestApi getRestDao() {
return getInstance().create(RestApi.class);
}
}

它使用此接口:

public interface RestApi {
@GET("/plan/list")
Call<List<FlightPlan>> getFlightPlanList();
}

代码中不起作用的部分是:

public MutableLiveData<List<FlightPlan>> getFlightPlans() {
Log.d(TAG, "GET_FLIGHT_PLANS");
final MutableLiveData<List<FlightPlan>> data = new MutableLiveData<>();
mRestApi.getFlightPlanList().enqueue(new Callback<List<FlightPlan>>() {
@Override
public void onResponse(Call<List<FlightPlan>> call, Response<List<FlightPlan>> response) {
if (response.code() == 200) {
List<FlightPlan> temp = response.body();
for (FlightPlan flightPlan : temp) {
Log.d(TAG + "res", flightPlan.toString());
}
data.setValue(response.body());
Log.d(TAG + "res", response.toString());
}
}
@Override
public void onFailure(Call<List<FlightPlan>> call, Throwable t) {
List<FlightPlan> flightPlans = new ArrayList<>();
flightPlans.add(new FlightPlan(0, "Test", 3.551, 50.52, 3.55122, 50.52625));
data.setValue(flightPlans);
Log.d(TAG, t.getMessage());
}
});
return data;
}

这将返回一个空列表。我想我明白为什么:调用enqueue()方法发出了另一个线程中的请求,所以在这里我们返回数据而不等待结果。

所以我的问题是如何连接改造和我的视图模型?

嘿凯文只是对你的代码的一个小改动。而不是 MutableLiveData 从您的存储库返回 LiveData:

public LiveData<List<FlightPlan>> getFlightPlans() {
Log.d(TAG, "GET_FLIGHT_PLANS");
final MutableLiveData<List<FlightPlan>> data = new MutableLiveData<>();
mRestApi.getFlightPlanList().enqueue(new Callback<List<FlightPlan>>() {
@Override
public void onResponse(Call<List<FlightPlan>> call, Response<List<FlightPlan>> response) {
if (response.code() == 200) {
List<FlightPlan> temp = response.body();
for (FlightPlan flightPlan : temp) {
Log.d(TAG + "res", flightPlan.toString());
}
data.postValue(response.body());
Log.d(TAG + "res", response.toString());
}
}
@Override
public void onFailure(Call<List<FlightPlan>> call, Throwable t) {
List<FlightPlan> flightPlans = new ArrayList<>();
flightPlans.add(new FlightPlan(0, "Test", 3.551, 50.52, 3.55122, 50.52625));
data.postValue(flightPlans);
Log.d(TAG, t.getMessage());
}
});
return data;
}

如果我这样做:

public LiveData<List<FlightPlan>> getFlightPlans() {
Log.d(TAG, "GET_FLIGHT_PLANS");
final MutableLiveData<List<FlightPlan>> data = new MutableLiveData<>();

List<FlightPlan> flightPlans = new ArrayList<>();
flightPlans.add(new FlightPlan(5, "Test5", 3.551, 50.52, 3.55122, 50.52625));
data.setValue(flightPlans);
Log.d(TAG, data.getValue().toString());

mRestApi.getFlightPlanList().enqueue(new Callback<List<FlightPlan>>() {
@Override
public void onResponse(Call<List<FlightPlan>> call, Response<List<FlightPlan>> response) {
if (response.code() == 200) {
List<FlightPlan> temp = response.body();
for (FlightPlan flightPlan : temp) {
Log.d(TAG + "res", flightPlan.toString());
}
data.setValue(response.body());
Log.d(TAG + "res", response.toString());
}
}
@Override
public void onFailure(Call<List<FlightPlan>> call, Throwable t) {
List<FlightPlan> flightPlans = new ArrayList<>();
flightPlans.add(new FlightPlan(0, "Test", 3.551, 50.52, 3.55122, 50.52625));
data.setValue(flightPlans);
Log.d(TAG, t.getMessage());
}
});
return data;
}

我可以在 Logcat 中看到默认值,以及来自我的休息服务器的两个值,但字符串是空值,int/doubles 为 0,它不会将两个休息条目添加到回收器视图中。

这是我的活动代码:

public class FlightPlanActivity extends AppCompatActivity implements View.OnClickListener, SwipeRefreshLayout.OnRefreshListener, LifecycleOwner {
private static final String TAG = "FlightPlanActivity";
private FlightPlanAdapter mFlightPlanAdapter;
private FlightPlanViewModel mFlightPlanViewModel;
/**
* UI
*/
private FloatingActionButton mAddPlanButton;
private RecyclerView mRecyclerView;
private SwipeRefreshLayout mSwipeRefreshLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_flight_plan);
Log.d(TAG, "onCreate called");
initUI();
}
private void initUI() {
this.setTitle("Flight Plans");
mRecyclerView = findViewById(R.id.flight_plan_list);
mAddPlanButton = findViewById(R.id.add_flight_plan);
mSwipeRefreshLayout = findViewById(R.id.refresh_flight_plan_list);
mAddPlanButton.setOnClickListener(this);
mSwipeRefreshLayout.setOnRefreshListener(this);
mFlightPlanAdapter = new FlightPlanAdapter();
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(mFlightPlanAdapter);
mFlightPlanViewModel = ViewModelProviders.of(this).get(FlightPlanViewModel.class);
mFlightPlanViewModel.getFlightPlans().observe(this, (flightPlans) -> {
Log.d(TAG, "ON_CHANGED");
mFlightPlanAdapter.setFlightPlans(flightPlans);
});
}
@Override
public void onClick(View v) {
if (v.getId() == mAddPlanButton.getId()) {
// TODO: A implémenter
}
}
@Override
public void onRefresh() {
mFlightPlanAdapter.setFlightPlans(mFlightPlanViewModel.getFlightPlans().getValue());
mSwipeRefreshLayout.setRefreshing(false);
}
}

那么,如果我这样做,当有响应时会发生什么?

public LiveData<List<FlightPlan>> getFlightPlans() {
Log.d(TAG, "GET_FLIGHT_PLANS");
MutableLiveData<List<FlightPlan>> data = new MutableLiveData<>();
mRestApi.getFlightPlanList().enqueue(new Callback<List<FlightPlan>>() {
@Override
public void onResponse(Call<List<FlightPlan>> call, Response<List<FlightPlan>> response) {
if (response.code() == 200) {
data.setValue(response.body());
}
}
@Override
public void onFailure(Call<List<FlightPlan>> call, Throwable t) {
// Do something
}
});
return data;
}

我你运行它,有一个返回的空对象,但如果有响应,它会返回一些东西吗?

我试过了:

public LiveData<List<FlightPlan>> getFlightPlans() {
Log.d(TAG, "GET_FLIGHT_PLANS");
MutableLiveData<List<FlightPlan>> data = new MutableLiveData<>();
List<FlightPlan> flightPlans;
try {
Response<List<FlightPlan>> response = mRestApi.getFlightPlanList().execute();
if (response.isSuccessful()) {
flightPlans = response.body();
} else {
Log.d(TAG, "Can't get data !");
throw new Exception("Can't get data !");
}
} catch (Exception e) {
e.printStackTrace();
flightPlans = new ArrayList<>();
flightPlans.add(new FlightPlan(5, "Test5", 3.551, 50.52, 3.55122, 50.52625));
}
data.setValue(flightPlans);
Log.d(TAG, data.getValue().toString());
return data;
}

现在它在执行行上崩溃,因为我在主线程中启动它。 所以我必须做一个异步任务,但在哪里?

其他选项:像一开始一样做一个异步任务,把一个二传手放到模型视图对象,当有响应时,我调用二传手。这样做好吗?

谢谢你给我的叮叮!这是非常有帮助的。

编辑:为什么谷歌文档上有这个代码:

public class UserRepository {
private Webservice webservice;
// ...
public LiveData<User> getUser(int userId) {
// This isn't an optimal implementation. We'll fix it later.
final MutableLiveData<User> data = new MutableLiveData<>();
webservice.getUser(userId).enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
data.setValue(response.body());
}
// Error case is left out for brevity.
});
return data;
}
}

这意味着做这样的事情可以吗?

溶液!

编辑:

如何将 ViewModel 与存储库连接,以便将数据传播到视图(MVVM、Livedata)

这对我有很大帮助!!

我找到了解决方案!我很愚蠢:我在 gradle 文件中插入了旧的依赖项!

最新更新