MVVM 架构,ViewModel和LiveData

Posted 若兰明月

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MVVM 架构,ViewModel和LiveData相关的知识,希望对你有一定的参考价值。

MVVM 架构,ViewModel和LiveData(一)

标签(空格分隔): 翻译计划 android开发


原文链接

正文

在Google I/O之间,Google推出了包含LiveData和ViewModel的组件架构,这有助于开发者们使用MVVM开发Android应用程序。这篇文章旨在讲述该组件如何融汇在使用MVVM模式开发Android应用程序。

MVVM简单介绍

如果你很熟悉MVVM架构,那么你可以快速跳过本小节知识点。

MVVM是增强关注点分离的体系结构模式之一,它允许将用户界面逻辑从业务(或者后端)逻辑中分离开来,他的目标(和MVC等其他目标)是为了实现”保持UI代码简单化,不涉及更多的业务逻辑,以便于开发者更好的控制和管理”。

MVVM主要有以下几个层次:

  • 1、Model层
    • Model层表示用户程序的数据和业务逻辑,这一层的的推荐的实现策略之一就是观测数据的变化并传递出去(供谁使用),使其从ViewModel或者其他观察者/消费者中完全解耦.(这将在我们文章下面的MVVM事例中进行说明).
  • 2、ViewModel层
    • ViewModel是和Model(数据层)进行交互,并且ViewMode可以被View观察.ViewModel可以选择性地为视图提供钩子以将事件传递给模型.该层的一个重要实现策略是将Model与View分离,即ViewModel不应该意识到与谁交互的视图.
  • 3、View层
    • 此模式中的视图角色是观察(或订阅)ViewMode,观察数据b变化,以便于获取数据去更新UI元素.

下图显示了MVVM组件和基本交互。

LiveData

如上所述,LiveData是新引入的组件架构之一,LiveData是一个可以被观察的数据持有者.这也就意味着应用中的组件能够观察LiveData对象的更改,而无需在它们之间创建明确的和严格的依赖关系。这将完全分离LiveData对象使用者和LiveData对象生产者。

除此之外,LiveData还有一个很大的好处,LiveData遵守应用程序组件(活动,片段,服务)的生命周期状态,并进组件的生命周期管理,确保LiveData对象的内存泄漏.

根据Google文档,如果您已经在使用Rx或Agera等开源库,那么你可以继续使用它们而不是替换成LiveData.但在这种情况下,您有责任处理每个Android组件生命周期的对象分配和解除分配.

由于LiveData遵从Android的生命周期机制,这意味着除非LiveData主体(activity或fragment)处于活动状态(接收onStart()但未收到onStop()),否则它将不会调用其观察者回调.除此之外,当主体收到onDestroy()时,LiveData也会自动删除观察者防止内存泄漏.

LiveData也会将在下面的MVVM事例中进行说明.

ViewModel

ViewModel也是新引入的体系架构组件之一.架构组件提供了一个名为ViewModel的新类,它负责为UI / View准备数据.

ViewModel为您的MVVM模式中的ViewModel提供了一个很好的基类,因为ViewModel(及其子类AndroidViewModel)的扩展类会在配置更改期间自动保留其数据.这意味着,在配置更改后,此ViewModel所有数据可立即用于下一个活动(activity)或片段(fragment)实例.

下图显示了ViewModel组件的生命周期:

ViewModel也将会在下面的MVVM事例中进行说明。

应用事例

现在,让我们来看看最有趣的部分,让我们把上述的所有知识(组件)放在一个程序中.
此MVVM事例应用主要包含两个界面.
下面显示的第一个界面显示了Google GitHub上的项目列表.其中包含一些简要信息,例如标题,编程语言和watcher数量。

一旦用户点击了首页的item,GitHub项目的详细信息屏幕将会显示项目描述,编程语言,watcher数量,公开问题,创建和上次更新日期,最后显示克隆URL.

示例应用程序交互图

下图显示了示例应用程序的包结构

以下交互图显示了检索Google GitHub项目的应用场景之一的示例交互图。

如上图所示,每个图层都从其后续图层(Fragment(View) - > ViewModel - > Repository)观察LiveData,最后一旦检索到项目列表(或者有所变化),就会使用RecyclerView(ListView)适配器绑定显示项目列表.

Respository模块负责处理数据操作,通过这一点,Respository可以为程序的其余部分提供干净的API,并简化ViewModel的工作.
如果需要更新数据,Respository模块应该知道从哪里获取数据以及进行哪些API调用.它们可以被视为不同数据源(REST服务,数据库,XML文件等)之间的中介.

现在,让我们从下往上解释这些图层,从Model、ViewModel开始,最后用View来检索GitHub项目场景。

示例应用程序模型层

让我们从业务逻辑层开始,我们有两个模型对象

  • 1、Project.包含GitHub项目的信息,如id,名称,描述,创建日期等等
  • 2、User,包含GitHub项目所有者的用户信息.
    为了与GitHub RESTful API进行交互,我使用了我喜欢的Retrofit2来定义存储库包中的以下简单接口。
interface GitHubService 
    String HTTPS_API_GITHUB_URL = "https://api.github.com/";

    @GET("users/user/repos")
    Call<List<Project>> getProjectList(@Path("user") String user);

    @GET("/repos/user/reponame")
    Call<Project> getProjectDetails(@Path("user") String user, @Path("reponame") String projectName);

为了便于ViewModel的工作,创建一个ProjectRespository来与GitHub服务交互,并最终为ViewModel提供一个LiveData对象.以下代码片段显示了getProjectList()API实现.

public class ProjectRepository 
    private GitHubService gitHubService;

    //…

    public LiveData<List<Project>> getProjectList(String userId) 
        final MutableLiveData<List<Project>> data = new MutableLiveData<>();

        gitHubService.getProjectList(userId).enqueue(new Callback<List<Project>>() 
            @Override
            public void onResponse(Call<List<Project>> call, Response<List<Project>> response) 
                data.setValue(response.body());
            

            // Error handling will be explained in the next article …
        );

        return data;
    

    // …

ProjectRepository是ViewModel的数据提供者,它有getProjectList(),它简单地将响应包装到LiveData对象中.

为了简化本文的目的,错误处理被省略,并且将在下一篇文章中进行说明

示例应用程序ViewModel层

为了处理(接收)getProjectList()API,创建了ViewModel类(调用Repository API并可以为LiveData执行任何所需的数据转换).
以下代码片段显示了ProjectListViewModel类

public class ProjectListViewModel extends AndroidViewModel 
    private final LiveData<List<Project>> projectListObservable;

    public ProjectListViewModel(Application application) 
        super(application);

        // If any transformation is needed, this can be simply done by Transformations class ...
        projectListObservable = ProjectRepository.getInstance().getProjectList("Google");
    

    /**
     * Expose the LiveData Projects query so the UI can observe it.
     */
    public LiveData<List<Project>> getProjectListObservable() 
        return projectListObservable;
    

如上所示,我们的ProjectListViewModel类继承了AndroidViewModel,并在构造函数中调用getProjectList(“Google”)来检索Google GitHub项目.

在现实世界的情况下,在将结果数据传递到观察视图之前可能需要进行转换,为了进行转换,可以使用Transformation类,如以下文档中所示https://developer.android.com/topic/libraries/architecture/livedata.html#transformations_of_livedata

示例应用视图图层View

最后,让我们快速浏览一下这个应用程序的视图层,我们主要有一个名为MainActivity的Activity(活动),它负责处理代表应用程序视图的两个片段的导航.

  • 1、ProjectListFragment:其中显示了Google GitHub项目的列表界面
  • 2、ProjectFragment:它显示所选的GitHub项目详细信息

由于活动和片段被视为生命周期所有者,activity需要扩展LifecycleActivity,fragment需要扩展LifecycleFragment.但是,请务必记住LifecycleActivity和LifecycleFragment类都是临时实现,直到Lifecycle与支持库支持为止:https://developer.android.com/reference/android/arch/lifecycle/LifecycleActivity.html

现在,让我们继续我们的项目检索方案,查看ProjectListFragment这个界面,下面的代码片段显示了最重要的集成部分.

public class ProjectListFragment extends LifecycleFragment 
    private ProjectAdapter projectAdapter;

    //…

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) 
        super.onActivityCreated(savedInstanceState);
        final ProjectListViewModel viewModel =
                ViewModelProviders.of(this).get(ProjectListViewModel.class);

        observeViewModel(viewModel);
    

    private void observeViewModel(ProjectListViewModel viewModel) 
        // Update the list when the data changes
        viewModel.getProjectListObservable().observe(this, new Observer<List<Project>>() 
            @Override
            public void onChanged(@Nullable List<Project> projects) 
                if (projects != null) 
                    //…
                    projectAdapter.setProjectList(projects);
                
            
        );
    

    //…

如上代码所示,ProjectListFragment获取ProjectListViewModel数据对象,然后监听其getProjectListObservable()方法,以便获取Github项目列表。
最后,一旦检索到项目列表(有数据变化),它将被传递给projectAdapter(RecyclerView适配器),以显示RecyclerView组件中(更新UI).

这是对项目的一个端到端场景的解释,您可以在这里找到GitHub中提供的完整项目:

MVVM模式的重要指导原则

现在,重点介绍MVVM实现的一些重要指导原则:

  • 1、如示例中所示,ViewModels不会直接引用Views,因为如果这样做,ViewModels可能会超出View的生命周期,并且可能会发生内存泄漏
  • 2、建议Model和ViewModel中的桥梁LiveData公开其数据,因为LiveData遵守应用程序组件(活动、片段、服务)的生命周期状态并处理对象生命周期管理,以确保LiveData对象不泄漏

下一篇文章的相关知识点

故事尚未完成,因为有些事情需要处理,比如:

  • 1、Dependency Injection(依赖注入)
  • 2、Error Handling(错误处理)
  • 3、Caching(缓存)
  • 4、使用Room操作数据(数据库)
  • 5、Unit Testing(单元测试)
  • 6、Others (其他)

这将在MVVM的下一系列文章中进行说明,敬请关注.

以上是关于MVVM 架构,ViewModel和LiveData的主要内容,如果未能解决你的问题,请参考以下文章

MVVM 架构,ViewModel和LiveData

Android架构组件之ViewModel和LiveData

Android架构组件之ViewModel和LiveData

Android架构组件之ViewModel和LiveData

SwiftUI-MVVM

Android之MVVM架构之ViewModel + LiveData + DataBinding