MPC MVP 模式

[]MPC模式

这里写图片描述

()视图用来呈现模型,视图通常直接从模型中取得它需要显示的状态与数据。

()控制器取得用户的输入并解读其对模型的意思。

()模型持有所有的数据,状态,和程序逻辑。模型没有注意到视图和控制器,虽然它提供了操作和检索状态的接口,并发送状态改变通知观察者。

()模型使用观察者模式,以便观察者更新,同时保持两者之间解耦。

()控制器是视图的策略,视图可以使用不同的控制器实现,得到不同的行为。

()视图使用组合模式实现用户界面。

[]MVP模式

这里写图片描述

()View:视图层,在View层中只负责对数据的展示,提供友好的界面与用户进行交互。在Android开发中通常将Activity或者Fragment作为View层。

()Model:数据层。不仅仅是数据模型,它还负责对数据的存取操作,例如对数据库的读写,网络的数据的请求等。

()Presenter:它是连接View层与Model层的桥梁并对业务逻辑进行处理。在MVP架构中Model与View无法直接进行交互。所以在Presenter层它会从Model层获得所需要的数据,进行一些适当的处理后交由View层进行显示。这样通过Presenter将View与Model进行隔离,使得View和Model之间不存在耦合,同时也将业务逻辑从View中抽离。

 在MVP架构中将这三层分别抽象到各自的接口当中。通过接口将层次之间进行隔离,而Presenter对View和Model的相互依赖也是依赖于各自的接口。这点符合了接口隔离原则,也正是面向接口编程。在Presenter层中包含了一个View接口,并且依赖于Model接口,从而将Model层与View层联系在一起。而对于View层会持有一个Presenter成员变量并且只保留对Presenter接口的调用,具体业务逻辑全部交由Presenter接口实现类中处理。

()分析谷歌官方示例todo‑mvp项目的addedittask包为例来了解MVP(https://github.com/googlesamples/android-architecture/tree/todo-mvp/)

Presenter基类

public interface BasePresenter {

void start();

}

 只有start()。该方法是用于Presenter从Model层获取数据并调用View中的方法改变界面显示。该方法一般是在Fragment中的onResume()中调用。

View基类

public interface BaseView<T> {

void setPresenter(T presenter);

}

 只有setPresenter(),对于View层会存在一个Presenter对象。该方法是View用来初始化Presenter对象。该方法一般是在Presenter中的构造函数中调用。

契约类:官方的mvp加入了***Contract类来统一管理View与Presenter的所有的接口,使得View与Presenter中有哪些功能很明确,维护简单。

public interface AddEditTaskContract {

interface View extends BaseView<Presenter> {

    void showEmptyTaskError();

    void showTasksList();

    void setTitle(String title);

    void setDescription(String description);

    boolean isActive();
}

interface Presenter extends BasePresenter {

    void saveTask(String title, String description);

    void populateTask();

    boolean isDataMissing();
}
}

View层

public class AddEditTaskActivity extends AppCompatActivity {

.......

private AddEditTaskPresenter mAddEditTaskPresenter;

.......

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.addtask_act);

    .......

    AddEditTaskFragment addEditTaskFragment =
    (AddEditTaskFragment) getSupportFragmentManager().findFragmentById(R.id.contentFrame);

   .......

    if (addEditTaskFragment == null) {
        addEditTaskFragment = AddEditTaskFragment.newInstance();
    }
       .......

    // Create the presenter
    mAddEditTaskPresenter = new AddEditTaskPresenter(
            taskId,
            Injection.provideTasksRepository(getApplicationContext()),
            addEditTaskFragment,
            shouldLoadDataFromRepo);
}
@Override
protected void onSaveInstanceState(Bundle outState) {

      ......

    outState.putBoolean(SHOULD_LOAD_DATA_FROM_REPO_KEY, mAddEditTaskPresenter.isDataMissing());
    super.onSaveInstanceState(outState);
}
}

()AddEditTaskActivity并没有实现任何接口,只是加载Fragment对象(AddEditTaskFragment addEditTaskFragment),初始化Presenter对象(AddEditTaskPresenter mAddEditTaskPresenter)。在onSaveInstanceState()中调用Presenter对象的isDataMissing()。

()将Fragment对象(addEditTaskFragment)作为Presenter对象的构造函数参数被传入,这样就可以在Presenter对象中调用View对象的方法。

public class AddEditTaskFragment extends Fragment implements AddEditTaskContract.View {

   ......

public static AddEditTaskFragment newInstance() {
    return new AddEditTaskFragment();
}

@Override
public void onResume() {
    super.onResume();
    mPresenter.start();
}

@Override
public void setPresenter(@NonNull AddEditTaskContract.Presenter presenter) {
    mPresenter = checkNotNull(presenter);
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

   ......

    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mPresenter.saveTask(mTitle.getText().toString(), mDescription.getText().toString());
        }
    });
}

......

@Override
public void showEmptyTaskError() {
    Snackbar.make(mTitle, getString(R.string.empty_task_message), Snackbar.LENGTH_LONG).show();
}

@Override
public void showTasksList() {
    getActivity().setResult(Activity.RESULT_OK);
    getActivity().finish();
}

@Override
public void setTitle(String title) {
    mTitle.setText(title);
}

@Override
public void setDescription(String description) {
    mDescription.setText(description);
}

@Override
public boolean isActive() {
    return isAdded();
}
}

()AddEditTaskFragment实现View接口(AddEditTaskContract.View),并持有Presenter对象(AddEditTaskContract.Presenter mPresenter),在显示时(onResume())和FloatingActionButton点击时(onActivityCreated()的点击事件中)分别调用Presenter的start()和saveTask()。

()其中setPresenter(AddEditTaskContract.Presenter presenter),showEmptyTaskError(),showTasksList(),setTitle(String title),setDescription(String description),isActive()是View接口实现方法。

()通过setPresenter()让View对象(AddEditTaskFragment)获得了Presenter实例(mPresenter)。

()官方对于采用Fragment的原因给出了两种解释。

Activity作为全局的控制者将Presenter于View联系在一起,把Fragment作为view,这样两者就能各司其职。

采用Fragment更有利于平板电脑的布局或者是多视图屏幕。

Presenter层

public class AddEditTaskPresenter implements AddEditTaskContract.Presenter,
    TasksDataSource.GetTaskCallback {

@NonNull
private final TasksDataSource mTasksRepository;

@NonNull
private final AddEditTaskContract.View mAddTaskView;

   ......

public AddEditTaskPresenter(@Nullable String taskId,@NonNull TasksDataSource tasksRepository,
@NonNull AddEditTaskContract.View addTaskView, boolean shouldLoadDataFromRepo) {

    ......

    mTasksRepository = checkNotNull(tasksRepository);
    mAddTaskView = checkNotNull(addTaskView);

    ......

    mAddTaskView.setPresenter(this);
}

@Override
public void start() {
    if (!isNewTask() && mIsDataMissing) {
        populateTask();
    }
}

@Override
public void saveTask(String title, String description) {
    if (isNewTask()) {
        createTask(title, description);
    } else {
        updateTask(title, description);
    }
}

@Override
public void populateTask() {
    if (isNewTask()) {
        throw new RuntimeException("populateTask() was called but task is new.");
    }
    mTasksRepository.getTask(mTaskId, this);
}

@Override
public void onTaskLoaded(Task task) {

    if (mAddTaskView.isActive()) {
        mAddTaskView.setTitle(task.getTitle());
        mAddTaskView.setDescription(task.getDescription());
    }
    mIsDataMissing = false;
}

@Override
public void onDataNotAvailable() {

    if (mAddTaskView.isActive()) {
        mAddTaskView.showEmptyTaskError();
    }
}

@Override
public boolean isDataMissing() {
    return mIsDataMissing;
}

private boolean isNewTask() {
    return mTaskId == null;
}

private void createTask(String title, String description) {
    Task newTask = new Task(title, description);
    if (newTask.isEmpty()) {
        mAddTaskView.showEmptyTaskError();
    } else {
        mTasksRepository.saveTask(newTask);
        mAddTaskView.showTasksList();
    }
}

private void updateTask(String title, String description) {
    if (isNewTask()) {
        throw new RuntimeException("updateTask() was called but task is new.");
    }
    mTasksRepository.saveTask(new Task(title, description, mTaskId));
    mAddTaskView.showTasksList(); 
}
}

()AddEditTaskPresenter实现Presenter接口(AddEditTaskContract.Presenter)和GetTaskCallback接口(TasksDataSource.GetTaskCallback ),其中GetTaskCallback是Model层回调接口。AddEditTaskPresenter持有View层对象(AddEditTaskContract.View mAddTaskView)和Model层对象(TasksDataSource mTasksRepository)。并在构造函数中初始化,同时在构造函数中调用setPresenter()让View对象初始化Presenter对象。

()在Presenter的start()调用Model层对象(TasksDataSource)的getTask(),

()在Presenter的saveTask()中,如果没有新的任务,调用createTask()创建新任务,如果有新的任务,调用updateTask()修改任务。

在createTask()中,如果任务是空的,调用View层对象(AddEditTaskFragment)的showEmptyTaskError(),如果任务不是空的,调用Model层对象(TasksDataSource)的saveTask()和View层对象(AddEditTaskFragment)的showTasksList()。

在updateTask()中,如果没有新的任务,抛出异常,如果有新的任务,调用Model层对象(TasksDataSource)的saveTask()和View层对象(AddEditTaskFragment)的showTasksList()。

()在Presenter的isDataMissing()被调用时。

()onTaskLoaded()和onDataNotAvailable()是实现GetTaskCallback接口的方法,主要是Model层对象(TasksDataSource)操作数据后被调用。

()onTaskLoaded()和onDataNotAvailable()中调用View层对象(AddEditTaskFragment)的一些方法。

Model层

public interface TasksDataSource {

......

interface GetTaskCallback {

    void onTaskLoaded(Task task);

    void onDataNotAvailable();
}

......

void getTask(@NonNull String taskId, @NonNull GetTaskCallback callback);

void saveTask(@NonNull Task task);

......

}


public class TasksLocalDataSource implements TasksDataSource {

......

@Override
public void getTask(@NonNull final String taskId, @NonNull final GetTaskCallback callback) {
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            final Task task = mTasksDao.getTaskById(taskId);

            mAppExecutors.mainThread().execute(new Runnable() {
                @Override
                public void run() {
                    if (task != null) {
                        callback.onTaskLoaded(task);
                    } else {
                        callback.onDataNotAvailable();
                    }
                }
            });
        }
    };

    mAppExecutors.diskIO().execute(runnable);
}

@Override
public void saveTask(@NonNull final Task task) {
    checkNotNull(task);
    Runnable saveRunnable = new Runnable() {
        @Override
        public void run() {
            mTasksDao.insertTask(task);
        }
    };
    mAppExecutors.diskIO().execute(saveRunnable);
}

......

}

()saveTask()对数据进行操作。
()getTask()如果数据进行操作成功调用GetTaskCallback接口的onTaskLoaded(),如果数据进行操作失败调用GetTaskCallback接口的onDataNotAvailable()。

()MVP模式的不同实现方式

[] 谷歌提供的MVP模式主要思想(Activity或Fragment为View):

定义一个View层接口,让Activity或Fragment实现View层接口;
定义一个Presenter层接口,让其子类实现Presenter;
在View实现类Activity或Fragment中包含Presenter对象,并在Presenter的构造方法中传入View对象;

主要是将Activity或Fragment看做View,
优点:
()Presenter层逻辑的复用

这样可能会存在的问题:
(1)Activity作为Context总会有一些业务逻辑,比如发送Intent,启动Service和执行FragmentTransisitons等这些逻辑在View层中不合理。因为这些需要依赖Context。
(2)Activity或Fragment作为View不能复用,需要多次的去在每个Activity或Fragment做一些初始化View的操作,每个界面都要写一遍。

[]新思路(Activity或Fragment看做Presenter)

将Activity或Fragmen(还可以是Adapter)作为Presenter层,Presenter层包含一个View层的类(ViewDelegate对象)来间接操作View层对外提供的方法,从而做到完全解耦视View层 。

优点:
(1)可以使用Activity本身的生命周期去处理逻辑,而不需要强加给另一个包含类(Presenter对象),甚至记忆额外自定义的生命周期。
(2)独立的View对象可以很好的传递给Presenter层(Activity或者Fragment),而不需要改任何代码。可以让View层复用。

这样可能会存在的问题:
()视图逻辑不能复用。

新思路的具体实现可以参考文章(数据绑定可以忽略,因为DataBinding本身支持双向绑定):
https://github.com/kymjs/TheMVP

参考以下文章:

Google Android架构蓝图
https://github.com/googlesamples/android-architecture

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值