[英]MVVM with Retrofit - How to deal with a lot of LiveData in Repository?
I'm following this tutorial on using MVVM with Retrofit我正在按照本教程使用 MVVM 和 Retrofit
https://medium.com/@ronkan26/viewmodel-using-retrofit-mvvm-architecture-f759a0291b49 https://medium.com/@ronkan26/viewmodel-using-retrofit-mvvm-architecture-f759a0291b49
where the user places MutableLiveData inside the Repository class:用户将 MutableLiveData 放置在存储库 class 中的位置:
public class MovieRepository {
private static final ApiInterface myInterface;
private final MutableLiveData<EntityMovieOutputs> listOfMovies = new MutableLiveData<>();
private static MovieRepository newsRepository;
public static MovieRepository getInstance(){
if (newsRepository == null){
newsRepository = new NewsRepository();
}
return movieRepository;
}
public MovieRepository(){
myInterface = RetrofitService.getInterface();
}
I'm building a simple app and what I noticed is my repository class is quickly being filled with a lot of MutableLiveData objects.我正在构建一个简单的应用程序,我注意到我的存储库 class 很快就被很多 MutableLiveData 对象填充了。 Is this actually the correct way to implement MVVM, LiveData, and the Repository pattern?这实际上是实现 MVVM、LiveData 和存储库模式的正确方法吗?
Edit1:________________________________________________编辑 1:________________________________________________
I've created an AdminLiveData
object that just holds the LiveData and has getters.我创建了一个AdminLiveData
object,它只保存 LiveData 并具有吸气剂。
But how would I get reference to the ViewModel
inside my AdminRepo
class so I can notify the LiveData
inside the ViewModel when the Retrofit Network call is complete?但是,如何在我的AdminRepo
LiveData
中获取对ViewModel
的引用,以便在 Retrofit 网络调用完成时通知 ViewModel 中的 LiveData?
private AdminService adminService;
public AdminRepo(Application application) {
BaseApplication baseApplication = (BaseApplication) application;
RetrofitClient client = baseApplication.getRetrofitClient();
adminService = client.getRetrofit().create(AdminService.class);
//AdminViewModel viewModel = (AdminViewModel) ....
// Not sure how to get reference to the viewmodel here so I can get the
// LiveData object and call postValue after the retrofit calls
}
public void getFirstPageMembers(int offset, int limit) {
adminService.getUsersPaginitation(offset, limit).enqueue(new Callback<List<UserInfo>>() {
@Override
public void onResponse(@NonNull Call<List<UserInfo>> call, @NonNull Response<List<UserInfo>> response) {
if (response.body() != null) {
//firstPageLiveData.postValue(response.body());
//Since I create the LiveData inside the ViewModel class
//instead, how do I get reference to the ViewModel's LiveData?
}
}
@Override
public void onFailure(@NonNull Call<List<UserInfo>> call, @NonNull Throwable t) {
//firstPageLiveData.postValue(null);
}
});
}
The AdminViewModel
: AdminViewModel
:
public class AdminActivityViewModel extends AndroidViewModel {
private AdminRepo repo;
private AdminLiveData adminLiveData = new AdminLiveData();
public AdminActivityViewModel(@NonNull Application application) {
super(application);
repo = new AdminRepo(application);
}
How do I get reference to the AdminViewModel
from inside my AdminRepo
class?如何从我的AdminRepo
class 中获取对AdminViewModel
的引用?
Repository objects in android projects should be thought of as gateways to the outer world. android 项目中的存储库对象应被视为通往外部世界的网关。 Communication with persistence facilities(Network, SQLite, Shared Pref) takes place in this layer.与持久性设施(网络、SQLite、共享首选项)的通信发生在这一层。 Because of that incoming data aren't supposed to conform to the android environment.因为传入的数据不应该符合 android 环境。 For example, a string date field in incoming DTO should be converted to a date object using local date-time, you might need to save data coming from server to local DB.例如,传入 DTO 中的字符串日期字段应使用本地日期时间转换为日期 object,您可能需要将来自服务器的数据保存到本地 DB。 Additionally, other data-related tasks can be performed in this layer like caching in memory.此外,可以在这一层执行其他与数据相关的任务,例如 memory 中的缓存。
ViewModels represent the data that is shown in the user interface. ViewModel 表示用户界面中显示的数据。 Data in this layer should be ready to be presented on the screen.该层中的数据应该准备好在屏幕上呈现。 For example, a view might require data coming from two different HTTP requests, you should merge incoming data in this layer.例如,一个视图可能需要来自两个不同的 HTTP 请求的数据,您应该在这一层合并传入的数据。 (Still, you can separate responsibilities further. If these two requests are part of a single task or purpose, you can do this operation in the use case layer. ) From the android perspective, view models have more responsibility like preventing data from being destroyed in configuration changes. (不过,您可以进一步分离职责。如果这两个请求是单个任务或目的的一部分,您可以在用例层执行此操作。)从 android 的角度来看,视图模型具有更多的责任,例如防止数据被破坏在配置更改中。 In view models, it is recommended that data should be presented to the view layer by a LiveData.在视图模型中,建议数据应通过 LiveData 呈现给视图层。 It is due to fact that LiveData keeps the last state of the data and it is aware of the view layer's lifecycle (If it is used properly).这是因为 LiveData 保留了数据的最后一个 state 并且它知道视图层的生命周期(如果使用得当)。
First of all, the repository layer mustn't be aware of the existence of any view model so you should not keep a reference of a view model in the repository layer.首先,存储库层必须不知道任何视图 model 的存在,因此您不应在存储库层保留视图 model 的引用。 There are some reasons for it,有一些原因,
Of course, we need some kind of reference to the view model to notify it when a request is completed but we should do this implicitly in a systematic way rather than a direct reference.当然,我们需要某种对视图 model 的引用,以便在请求完成时通知它,但我们应该以系统的方式隐式执行此操作,而不是直接引用。
Callback: It is an old fashion way of sending data back to the view model.回调:这是一种将数据发送回视图 model 的老式方式。 Using callbacks extensively in your codebase causes callback hell that is not wanted.在代码库中广泛使用回调会导致不需要的回调地狱。 Additionally, the structured canceling mechanism is hard to implement using callbacks.此外,结构化取消机制很难使用回调实现。
LiveData: At first glance, it seems like a great fit for this purpose but it isn't. LiveData:乍一看,它似乎非常适合此目的,但事实并非如此。 The reasons can be listed as原因可以列举如下
In your case, it is especially bad practice because HTTP requests should not change the state of your repository object.在您的情况下,这是特别糟糕的做法,因为 HTTP 请求不应更改存储库 object 的 state。 You use LiveData as a kind of cache but there is no such requirement for this so you should avoid this.您将 LiveData 用作一种缓存,但对此没有这样的要求,因此您应该避免这种情况。 Still, if you need to use LiveData in your repo, you should either pass a MutableLiveData to your request method as a parameter so you can post the response via this LiveData or return a LiveData in your request method.尽管如此,如果您需要在您的存储库中使用 LiveData,您应该将 MutableLiveData 作为参数传递给您的请求方法,以便您可以通过此 LiveData 发布响应或在您的请求方法中返回 LiveData。
RxJava: It is one of the options. RxJava:它是选项之一。 It supports one-shot requests(Single), hot streams(Subject), and cold streams(Observable).它支持一次性请求(Single)、热流(Subject)和冷流(Observable)。 It supports structured canceling in some way(CompositeDisposable).它以某种方式支持结构化取消(CompositeDisposable)。 It has a stable API and has been used commonly for years.它有一个稳定的 API 并且已经普遍使用了多年。 It also makes many different network operations easier such as parallel requests, sequential requests, data manipulation, thread switching, and more with its operators.它还通过其运算符使许多不同的网络操作变得更容易,例如并行请求、顺序请求、数据操作、线程切换等。
Coroutines: It is another option and, in my opinion, the best.协程:这是另一种选择,在我看来,它是最好的。 Although its API is not completely stable, I have used it in many different projects and I haven't seen any problem.虽然它的 API 并不完全稳定,但我在很多不同的项目中使用过它,我没有发现任何问题。 It supports one-shot requests (suspend functions), hot streams (Channels and Stateflow), and cold streams(Flow).它支持一次性请求(挂起函数)、热流(Channels 和 Stateflow)和冷流(Flow)。 It is really useful in projects requiring complex data flows.它在需要复杂数据流的项目中非常有用。 It is a built-in feature in Kotlin with all operators.它是 Kotlin 中所有运算符的内置功能。 It supports structured concurrency in a really elegant way.它以一种非常优雅的方式支持结构化并发。 It has many different operator functions and it is easier to implement new operator functions compare to RxJava.它有许多不同的运算符函数,与 RxJava 相比,它更容易实现新的运算符函数。 It also has useful extension functions to use with ViewModel.它还具有与 ViewModel 一起使用的有用扩展功能。
To sum up, the repository layer is a gateway for incoming data, this is the first place where you manipulate data to conform requirements of your application as I have mentioned above.总而言之,存储库层是传入数据的网关,这是您操作数据以符合我上面提到的应用程序要求的第一个地方。 The operations that could be done in this layer can be listed shortly as mapping incoming data, deciding where to fetch data (local or remote source), and caching.可以在这一层中完成的操作可以简单地列出为映射传入数据、决定从哪里获取数据(本地或远程源)和缓存。 There are many options to pass data back to class requesting the data but RxJava and Coroutines are better than others as I have explained above.有许多选项可以将数据传回 class 请求数据,但 RxJava 和 Coroutines 比其他更好,正如我在上面解释的那样。 In my opinion, if you are not familiar with both of them, put your effort into Coroutines.在我看来,如果你对它们都不熟悉,那就把你的精力放在 Coroutines 上。
The solution you're looking for depends on how your app is designed.您正在寻找的解决方案取决于您的应用程序的设计方式。 There are several things you can try out:您可以尝试以下几件事:
LiveData<ScreenState>
and you just have to map your entities.这样你就有了一个LiveData<ScreenState>
并且你只需要 map 你的实体。Additionaly you could use coroutines with retrofit as coroutines are recomended way now for handling background operations and have Kotlin support if you wanted to give it a try.另外,您可以将协程与 retrofit 一起使用,因为协程现在被推荐用于处理后台操作,并且如果您想尝试一下,则支持 Kotlin。
Also these links might halpe you when exploring different architectures or solutions for handling your problem architecture-components-samples or architecture-samples (mostly using kotlin though).此外,在探索不同的架构或解决方案来处理您的问题架构组件示例或架构示例时,这些链接可能会阻碍您(尽管主要使用 kotlin)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.