【android-architecture】todo-mvp

来源:互联网 发布:暗黑破坏神3数据库app 编辑:程序博客网 时间:2024/05/18 14:27

MVP简介

MVP 对应一个应用分成三个基础的部分
Model层 负责处理应用的数据部分
View层 负责应用的界面绘制和用户交互
Presenter计算层 负责连接View和Model,也负责操控View

MVP 的一些基础规则

  1. View只负责根据Presenter的计算结果展示对应的界面
  2. View将用户的动作反馈给Presenter
  3. View永远不与Model交互
  4. Presenter负责解析View的请求并计算后通知View显示
  5. Model负责从本地或者网络拉取数据

todo-mvp

image

这个例子中每个界面由以下四个部分实现
1. Contract 定义View和Presenter之间的联系,其实是定义所有View和Presenter的相关操作的接口
2. Activity 创建Presenter和Fragment
3. Fragment mvp中的view层,实现了Contract中的View接口,负责界面的展示
4. Presenter 实现Contract中对应的Presenter接口

代码实现

todo-mvp实现

首先看看两个View和Presenter的两个基类BaseViewBaseView,都只有一个方法,所有的View都实现BaseView,通过setPresenter可以让View持有Presenter,Presenter都实现BasePresenter,在start方法中调用初始化数据的操作。

public interface BaseView<T> {    void setPresenter(T presenter);}public interface BasePresenter {    void start();}

demo是一个简单的备忘录,每个文件夹是一个界面,这个demo中有四个界面,添加和编辑界面,统计界面,任务详情,任务列表,以任务详情页为例

任务详情

可以看到界面上的功能有 编辑,删除,完成(CheckBox选中),任务置为活跃(CheckBox取消选中),可以抽象出对应的Presenter四个方法,见TaskDetailContract.Presenter

根据task展示的各种状态View抽象出的接口见TaskDetailContract.View,在fragment的resume方法中调用present的start方法,委托presenter开始准备数据,presenter受到委托后调用model层的方法获取数据,并调用View的setLoadingIndicator方法将View置成加载中的状态,等数据加载完成后根据是否有数据决定调用view的显示数据方法还是空页面方法,这样就实现了之前所说的view只绘制相应界面,presenter决定显示什么界面,model只负责获取数据,但时presenter决定什么时候获取,用户其他的操作也是和加载数据一样按照上述的流程

/** * This specifies the contract between the view and the presenter. */public interface TaskDetailContract {    interface View extends BaseView<Presenter> {        void setLoadingIndicator(boolean active);        void showMissingTask();        void hideTitle();        void showTitle(String title);        void hideDescription();        void showDescription(String description);        void showCompletionStatus(boolean complete);        void showEditTask(String taskId);        void showTaskDeleted();        void showTaskMarkedComplete();        void showTaskMarkedActive();        boolean isActive();    }    interface Presenter extends BasePresenter {        void editTask();        void deleteTask();        void completeTask();        void activateTask();    }}

在activity中分别初始化View和Presenter

TaskDetailActivity.java protected void onCreate(Bundle savedInstanceState) {     String taskId = getIntent().getStringExtra(EXTRA_TASK_ID);        //初始化View        TaskDetailFragment taskDetailFragment = (TaskDetailFragment) getSupportFragmentManager()                .findFragmentById(R.id.contentFrame);        if (taskDetailFragment == null) {            taskDetailFragment = TaskDetailFragment.newInstance(taskId);            ActivityUtils.addFragmentToActivity(getSupportFragmentManager(),                    taskDetailFragment, R.id.contentFrame);        }        // 初始化 presenter        new TaskDetailPresenter(                taskId,                Injection.provideTasksRepository(getApplicationContext()),                taskDetailFragment); } TaskDetailPresenter.java public class TaskDetailPresenter implements TaskDetailContract.Presenter {     public TaskDetailPresenter(@Nullable String taskId,                               @NonNull TasksRepository tasksRepository,                               @NonNull TaskDetailContract.View taskDetailView) {        mTaskId = taskId;        //获取数据仓库,也就是Model层的引用        mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null!");        //获取View层的引用        mTaskDetailView = checkNotNull(taskDetailView, "taskDetailView cannot be null!");        //将自己传给View层,这样View就有了presenter的引用        mTaskDetailView.setPresenter(this);    }    /**    *初始化数据    **/    @Override    public void start() {        openTask();    }    private void openTask() {        if (Strings.isNullOrEmpty(mTaskId)) {            mTaskDetailView.showMissingTask();            return;        }        mTaskDetailView.setLoadingIndicator(true);        mTasksRepository.getTask(mTaskId, new TasksDataSource.GetTaskCallback() {            @Override            public void onTaskLoaded(Task task) {                // The view may not be able to handle UI updates anymore                if (!mTaskDetailView.isActive()) {                    return;                }                mTaskDetailView.setLoadingIndicator(false);                if (null == task) {                //没有数据显示空页面                    mTaskDetailView.showMissingTask();                } else {                //数据加载完成后改变View显示状态                    showTask(task);                }            }            @Override            public void onDataNotAvailable() {                // The view may not be able to handle UI updates anymore                if (!mTaskDetailView.isActive()) {                    return;                }                mTaskDetailView.showMissingTask();            }        });    } } TaskDetailPresenter.java public class TaskDetailFragment extends Fragment implements TaskDetailContract.View {    //调用presenter的start方法开始加载数据     public void onResume() {            super.onResume();            mPresenter.start();        }        //保存presenter引用    @Override    public void setPresenter(@NonNull TaskDetailContract.Presenter presenter) {        mPresenter = checkNotNull(presenter);    }}
原创粉丝点击