Android Google官方MVP架构分析
写在前面
关于MVP模式的基本介绍与优缺点可以参见下面这篇文章:
本文的重点是对Google官方写的一个MVP架构实现的Demo进行简单的分析来看看谷歌实现的Android MVP架构是怎么搭建的。
谷歌官方的架构Demo地址:
本文所讲解的为:
https://github.com/googlesamples/android-architecture/tree/todo-mvp
需要读者参照源码查看本文。
我将这个todo应用的框架提炼出来(同时也意味着丢失了很多的实现细节,但可以将架构看得更加清晰),制作了一张伪UML
图(为了简化,没有遵循UML
的规范),下面我们参照着表中的内容进行分析:
BaseView与BasePresenter
可以看到它们是独立于包外的两个基础接口,之后的所有View
与Presenter
接口都将继承它们,所以应该将一些通用的方法写在这两个Base
接口中。
tasks包
整个app中tasks
、taskdetail
、statistics
三个包对应着的就是三个Activity
,可以看到每一个包中包含了对应的Activity
、View
、Presenter
与Contract
类和其他工具组件,通过这样的方式构成了应用的一个组成单元(每一个Activity
与其对应的View
和实现逻辑的Presenter
)。
图中我只展现了tasks
这一个包,其他的包内部的结构也是一样的。
TasksContract接口
TasksContract
接口包含两个接口,分别是继承了BaseView
与BasePresenter
的View
与Presenter
。
我们可以将Contract
接口视为管理View
与Presenter
需要实现的方法的汇总接口,这些方法在实例类中实际上都是通过接口来进行调用的,这样就可以避免依赖于某一个特定类的方法来进行处理,从而可以有多种实现View
与Presenter
的方式,便于进行单元测试(可以看到源代码中就有很多单元测试的内容,但是在这篇文章中我们将它们忽略)。
一切与更新UI有关的逻辑都应该放在TasksContract.View
接口中。
一切与业务有关的逻辑都应该放在TaskContract.Presenter
接口中。
TasksFragment与TasksPresenter
TasksFragment
与TaskPresenter
分别是TasksContract.View
与TaskContract.Presenter
接口的实例。
TaskActivity
在初始化时会先创建TasksFragment
实例,再将其作为构造参数传递给TaskPresenter
,TaskPresenter
在构造方法中又会调用TasksFragment
的setPresenter
方法将自身传递给TasksFragment
。这样Presenter
与View
就分别存有了一份对方的引用。
构造完成后,当用户与UI进行交互,View
一律调用Presenter
的相关方法来进行交互事件的处理或请求数据更新。如果有新的内容需要呈现在UI上,则由Presenter
调用View
的相关方法来进行更新。Presenter
则负责与上一级的数据存储池进行交互来更新数据或是获取新的数据。
可以看到Presenter
充当了一个“中介”,View
的所有请求都将交由Presenter
进行处理,而View
现在需要做的只有提供相应方法供Presenter
进行调用,避免了将大量业务逻辑写在View
中。同时也避免了View
与数据的直接交互,而是由Presenter
“单线操作”,降低了耦合度。
Data包
Task
这里的Task
是一个POJO
类,用于表示储存的数据。
source包
TaskDataSource接口
TaskDataSource
接口定义了所有可以的用于操作数据的对象的方法,换句话说,无论数据的来源是什么,我们都可以通过调用实现了这个接口的对象的方法来操纵数据。
GetTaskCallback与LoadTasksCallback
注意到用于获取数据的方法的参数都利用了callback
进行回调来传递数据。这样做主要因为数据的获取有可能是异步的,使用回调机制可以避免线程因为等待数据而阻塞。
local包与remote包
这两个包分别存放着一个实现了TaskDataSource
接口的类,他们就代表了从本地缓存获取数据与从远端获取数据。当然与获取数据有关的其他类也应该放在这个包下。
TaskRepository
有了从本地与远端获取数据的类,那么就应该有一个类对它们进行管理,我们希望的是有本地缓存时读取本地缓存,没有时就从远端的获取数据。在更为复杂的情况下,我们需要处理来自远端的请求并与本地的数据进行同步。
TaskRepository
就是用于管理所有的这些数据来源并统一成一个TaskDataSource
暴露给Presenter
来操作数据,而这些数据管理逻辑就被隐藏在了TaskRepository
中。
值得注意的是,源码中在TaskRepository
中还实现了一个内存缓存,可以避免从其他两个低速来源中获取数据。