【android-architecture】todo-mvp

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

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值