有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java MVVM的改进如何处理存储库中的大量实时数据?

我将按照本教程介绍如何使用MVVM进行改装

https://medium.com/@ronkan26/viewmodel-using-retrofit-mvvm-architecture-f759a0291b49

用户在存储库类中放置MutableLiveData的位置:

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

我正在构建一个简单的应用程序,我注意到我的repository类很快被许多可变的LiveData对象填充。这实际上是实现MVVM、LiveData和存储库模式的正确方法吗

enter image description here

编辑1:\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

我创建了一个AdminLiveData对象,它只保存LiveData和getter

enter image description here

但是,如何获得对AdminRepo类中ViewModel的引用,以便在改造网络调用完成时通知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);
            }
        });
    }

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

如何从AdminRepo类内部获取对AdminViewModel的引用


共 (2) 个答案

  1. # 1 楼答案

    您正在寻找的解决方案取决于应用程序的设计方式。您可以尝试以下几种方法:

    • 让你的应用程序模块化-正如@ADM所提到的,将你的存储库拆分为更小的存储库
    • 将实时数据移出存储库-在整个应用程序生命周期中,不需要将实时数据保存在存储库中(在您的示例中为单例),而可能只有少数屏幕需要不同的数据
    • 也就是说,将实时数据保存在视图模型中,这是最标准的方法。您可以看一下this article,它解释了改装ViewModel LiveData存储库模式
    • 如果您最终得到一个复杂的屏幕和许多实时数据对象,那么您仍然可以使用事件/状态/命令(可以随意调用)将实体映射到屏幕数据表示中,这些事件/状态/命令描述得非常好here。这样你就有了一个LiveData<ScreenState>,你只需要映射你的实体

    此外,您可以使用coroutines with retrofit,因为现在推荐使用协同路由来处理后台操作,如果您想尝试一下,还可以使用Kotlin支持

    此外,这些链接可能有助于您探索不同的体系结构或解决方案来处理问题architecture-components-samplesarchitecture-samples(不过主要使用kotlin)

  2. # 2 楼答案

    存储库和视图模型

    android项目中的存储库对象应该被视为通向外部世界的网关。与持久性设施(网络、SQLite、共享Pref)的通信在此层中进行。因此,传入的数据不应该符合android环境。例如,传入DTO中的字符串日期字段应使用本地日期时间转换为日期对象,您可能需要将来自服务器的数据保存到本地数据库。此外,其他与数据相关的任务也可以在这一层中执行,比如在内存中缓存

    ViewModels表示用户界面中显示的数据。该层中的数据应准备好显示在屏幕上。例如,一个视图可能需要来自两个不同HTTP请求的数据,您应该在此层中合并传入的数据。(不过,您可以进一步分离责任。如果这两个请求是单个任务或目的的一部分,您可以在用例层中执行此操作。)从android的角度来看,视图模型有更多的责任,比如防止数据在配置更改中被破坏。在视图模型中,建议使用LiveData将数据显示到视图层。这是因为LiveData保留了数据的最后状态,并且它知道视图层的生命周期(如果使用得当的话)

    存储库和ViewModel之间的通信

    首先,存储库层不能意识到任何视图模型的存在,因此不应在存储库层中保留视图模型的引用。有一些原因,

    • 大多数情况下,一组交互的单个存储库对象对于整个应用程序来说已经足够了。如果保留视图模型的引用,则会导致内存泄漏
    • 如果repo层中使用的服务器端API、本地存储和其他组件设计良好,那么与视图模型相比,存储库层不太容易发生更改
    • 存储库层的职责是从某处获取数据,这意味着它与视图相关的层无关

    当然,我们需要对视图模型进行某种引用,以便在请求完成时通知它,但我们应该以系统的方式隐式地这样做,而不是直接引用

    回调:这是一种将数据发送回视图模型的老式方式。在代码库中广泛使用回调会导致不需要的回调地狱。此外,结构化取消机制很难使用回调实现

    LiveData:乍一看,它似乎非常适合此用途,但事实并非如此。原因如下:

    • LiveData被设计为生命周期感知的数据持有者。这对于您来说是开销,因为您与该层中视图的生命周期没有任何关系
    • 在大多数情况下,数据获取操作是一次性的(就像您的情况一样),但LiveData是为流设计的
    • 它没有内置的对结构化取消的支持
    • 从体系结构的角度来看,不应将与android相关的类(如live data)导入存储库层。存储库类应该作为简单的Kotlin或java类实现

    在您的情况下,这是一种特别糟糕的做法,因为HTTP请求不应更改存储库对象的状态。您使用LiveData作为一种缓存,但是没有这样的要求,所以您应该避免这样做。尽管如此,如果您需要在repo中使用LiveData,您应该将MutableLiveData作为参数传递给您的请求方法,以便您可以通过该LiveData发布响应,或者在请求方法中返回LiveData

    RxJava:这是选项之一。它支持一次性请求(单个)、热流(主题)和冷流(可观察)。它支持st以某种方式进行结构化取消(可合成)。它有一个稳定的API,多年来一直被广泛使用。它还使许多不同的网络操作变得更容易,如并行请求、顺序请求、数据操作、线程切换等

    协同程序:这是另一种选择,在我看来是最好的选择。虽然它的API不是完全稳定的,但我已经在许多不同的项目中使用过它,我没有看到任何问题。它支持一次性请求(挂起功能)、热流(通道和状态流)和冷流(流)。它在需要复杂数据流的项目中非常有用。它是Kotlin中的内置功能,适用于所有操作员。它以一种非常优雅的方式支持结构化并发。它有许多不同的操作符函数,与RxJava相比,实现新的操作符函数更容易。它还具有用于ViewModel的有用扩展函数

    总而言之,存储库层是传入数据的网关,正如我前面提到的,这是您操作数据以符合应用程序要求的第一个地方。可以在该层中完成的操作可以很快列出,如映射传入数据、决定从何处获取数据(本地或远程源)以及缓存。有许多选项可以将数据传递回请求数据的类,但正如我前面所解释的,RxJava和协同路由比其他的要好。在我看来,如果你对这两个方面都不熟悉,那就把你的精力放在合作上