从google todo-mvp示例再次学习MVP

## 一、MVP简介 ![](https://user-gold-cdn.xitu.io/2018/2/28/161db3be446574b5?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) * Model: 数据层,负责与网络层和数据库层的逻辑交互。 * View: UI层,显示数据, 并向Presenter报告用户行为。 * Presenter: 从Model拿数据,应用到UI层,管理UI的状态,响应用户的行为。 ## 二、MVP优势 在学习todo-mvp之前,先了解一下MVP的优势。 * 分离了视图逻辑和业务逻辑,降低了耦合。 * Activity只处理生命周期的任务,代码变得更加简洁。 * 视图逻辑和业务逻辑分别抽象到了View和Presenter的接口中,提高代码的阅读性。 * Presenter被抽象成接口,可以有多种具体的实现,所以方便进行单元测试。 * 把业务逻辑抽到Presenter中去,避免后台线程引用着Activity导致Activity的资源无法被系统回收从而引起内存泄露和OOM。 ## 三、todo-mvp结构解析 ### 1.项目结构 ![](https://user-gold-cdn.xitu.io/2018/2/28/161db3be4475a306?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 从上图可以看出,todo-mvp是按照功能模块划分的。 其中tasks, taskdetail, addedittask, statistics是四个业务模块。 data是数据模块,其中具体的类`TasksRepository`担任Model层,负责远程和本地数据的获取。 `BasePresenter`和`BaseView`是presenter 和 view 的基类,在具体模块承担实际功能。最后,util是工具类集合。 ### 2.具体解析 在todoapp中,MVP的具体结构如下图所示: ![](https://user-gold-cdn.xitu.io/2018/2/28/161db3be44487d32?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 下面以tasks模块具体阐述上述图片中的实际作用关系。 **基类** public interface BasePresenter { void start(); } ` 其中`start()`方法的作用是presenter开始获取数据并调用view中方法改变界面显示,其调用时机是在Fragment类的`onResume`方法中。
`public interface BaseView {

        void setPresenter(T presenter);

    }
    `
其中`setPresenter()`方法作用是在将presenter实例传入view中,其**调用时机是presenter实现类的构造函数中**。 **契约类** 与之前使用的MVP实现不同,官方的实现中加入了契约类来统一管理view与presenter的所有的接口,这种方式使得view与presenter中有哪些功能,一目了然,维护起来也方便,同时使得view与presenter一一对应,并有效地减少类的数目。
`public interface TasksContract {

        interface View extends BaseView {

            void setLoadingIndicator(boolean active);

            void showTasks(List tasks);

            void showAddTask();

            void showTaskDetailsUi(String taskId);

            void showTaskMarkedComplete();

            void showTaskMarkedActive();

            void showCompletedTasksCleared();

            void showLoadingTasksError();

            void showNoTasks();

            void showActiveFilterLabel();

            void showCompletedFilterLabel();

            void showAllFilterLabel();

            void showNoActiveTasks();

            void showNoCompletedTasks();

            void showSuccessfullySavedMessage();

            boolean isActive();

            void showFilteringPopUpMenu();
        }

        interface Presenter extends BasePresenter {

            void result(int requestCode, int resultCode);

            void loadTasks(boolean forceUpdate);

            void addNewTask();

            void openTaskDetails(@NonNull Task requestedTask);

            void completeTask(@NonNull Task completedTask);

            void activateTask(@NonNull Task activeTask);

            void clearCompletedTasks();

            void setFiltering(TasksFilterType requestType);

            TasksFilterType getFiltering();
        }
    }
    `
**TasksActivity** Activity 在项目中是一个全局的控制者,负责创建 view 以及 presenter 实例,并将二者联系起来。
`        TasksFragment tasksFragment =
                    (TasksFragment) getSupportFragmentManager().findFragmentById(R.id.contentFrame);
            if (tasksFragment == null) {
                // 创建 fragment
                tasksFragment = TasksFragment.newInstance();
                ActivityUtils.addFragmentToActivity(
                        getSupportFragmentManager(), tasksFragment, R.id.contentFrame);
            }

            // 创建 presenter,TasksPresenter是TasksContract.Presenter 的实现类
           // 传入两个参数
           //1.TasksRepository实例,负责数据层  
           //2.tasksFragment,是TasksContract.View的实现类,即view实例
            mTasksPresenter = new TasksPresenter(
                    Injection.provideTasksRepository(getApplicationContext()), tasksFragment);
    `
其中,通过实例化`TasksPresenter`时,传入`tasksFragment`,使得在`TasksPresenter`中拥有view实例。同时,在实例化时初始化构造函数,调用了`setPresenter()`方法,使得view实例中拥有了presenter实例对象,使得两者联系起来。 `TasksPresenter`构造函数如下所示:
`    public TasksPresenter(@NonNull TasksRepository tasksRepository, @NonNull TasksContract.View tasksView) {
            mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null");
            mTasksView = checkNotNull(tasksView, "tasksView cannot be null!");

            mTasksView.setPresenter(this);
        }
    `
**TasksFragment** 将Fragment作为view层的实现类,使得Activity作为一个全局控制类来创建对象,而Fragment作为view,两者各司其职。同时,Fragment比较灵活,能够方便的处理界面适配的问题。
`public class TasksFragment extends Fragment implements TasksContract.View {
        ………..
        public static TasksFragment newInstance() {
            return new TasksFragment();
        }
        ………..
        @Override
        public void onResume() {
            super.onResume();
            mPresenter.start();
        }
        ………..
        @Override
        public void setPresenter(@NonNull TasksContract.Presenter presenter) {
            mPresenter = checkNotNull(presenter);
        }
        ………..
        @Override
        public boolean isActive() {
            return isAdded();
        }
        ………..
    }

对于 view 的实现TasksFragment,只挑一部分重要的方法来看。

*   `newInstance ()`方法,实例化TasksFragment对象。
*   `setPresenter()`方法继承于父类,通过该方法,view 获得了 presenter 得实例,从而可以调用 presenter 代码来处理业务逻辑。
*   在`onResume()`中,调用了 presenter 得`start()`方法,获取数据并操作view界面的显示。
*   `isActive()`方法,通过`isAdded()`判断对应Activity是否销毁。在Fragment在执行异步耗时操作后,如果调用Activity实例,应当先使用`isActive()`方法加以判断。





## 四、总结 通过对todo-mvp分析,再次了解学习了MVP。从google提供的例子中可以看出,MVP的实现较为简单,model、view和presenter各个职责明确,便于扩展维护。contract契约类的出现,使得model和presenter结构更加清晰明了。Activity和Fragment的配合,使得Activity职能更为简化,同时View的实现更加灵活。

你可能感兴趣的:(mvp,数据库,ui,谷歌,数据,Android,java)