Android中的MVP模式

Posted ZhangJianIsAStark

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android中的MVP模式相关的知识,希望对你有一定的参考价值。

一、MVP的基本概念
传统的android应用开发中,View层承载了太多的责任。
它需要完成界面的更新,复杂动画的渲染等UI相关操作,
还需要处理各种业务逻辑。

由于职责不单一,View层的代码往往显得很庞大。
随着功能的增加,View层代码的维护和升级将变得越来越困难。

为了更好的组织并对代码进行分层设计,
就出现了MVP模式。

MVP的全称是Model、View和Presenter。
从名称可以看出,MVP将整个应用分为三层。

其中:
视图(View)层,包含界面相关的功能,例如Activity、Fragment、View等,
专注于用户的交互,实现界面、动画等交互效果。
View层一般会持有Presenter层的引用,
并将非UI的逻辑操作委托给Presenter。

逻辑控制(Presenter)层,充当中间人的角色,用来隔离View和Model层。
它主要负责View层和Model层的控制和交互。

模型(Model)层,主要用于封装各种数据来源。

二、MVP与MVC的区别
MVP是MVC的延伸和改进,MVC的关系如下所示。

与MVP的关系图比较,容易看出,MVC和MVP最大的差异是:MVC中Model和View可以直接通信。
这其实就是造成Activity、Fragment等组件职责不够单一的原因。

MVP中的View层和Model层并没有直接通信,
而是通过中间人Presenter来间接通信,
Presenter和View以及Model的交互都是通过接口来进行的,
因此在符合接口规范的情况下,可以替换Presenter的实现。

三、MVP的开源实现
单纯依靠文字来描述MVP的思想比较单薄,
我们不妨来看看Google提供的示例代码TO-MVP
该工程中Activity的主要工作类似于:

@Override
protected void onCreate(Bundle savedInstanceState) 
    ......
    TasksFragment tasksFragment = (TasksFragment) getSupportFragmentManager()
            .findFragmentById(R.id.contentFrame);
    if (tasksFragment == null) 
        // Create the fragment
        tasksFragment = TasksFragment.newInstance();
        ActivityUtils.addFragmentToActivity(
                getSupportFragmentManager(), tasksFragment, R.id.contentFrame);
    

    // Create the presenter
    // 注意到Fragment被传入到Presenter的构造函数中,相当于绑定了
    mTasksPresenter = new TasksPresenter(
            Injection.provideTasksRepository(getApplicationContext()), tasksFragment);
    ............

从上述代码可以看出,Activity负责创建Fragment和Presenter。

我们再来看看TaskFragment的代码:

//实现View定义的接口
public class TasksFragment extends Fragment implements TasksContract.View 
    //Presenter的类型也是个接口
    private TasksContract.Presenter mPresenter;
    .......
    //关联Fragment和Presenter
    @Override
    public void setPresenter(@NonNull TasksContract.Presenter presenter) 
        mPresenter = checkNotNull(presenter);
    
    .......
    //容易看出,Fragment管理UI相关的工作
    //具体的逻辑全部交由Presenter
    @Override
    public void showFilteringPopUpMenu() 
        PopupMenu popup = new PopupMenu(getContext(),     
                getActivity().findViewById(R.id.menu_filter));
        popup.getMenuInflater().inflate(R.menu.filter_tasks, popup.getMenu());

        popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() 
            public boolean onMenuItemClick(MenuItem item) 
                switch (item.getItemId()) 
                    case R.id.active:
                        //实际逻辑给Presenter
                        mPresenter.setFiltering(TasksFilterType.ACTIVE_TASKS);
                        break;
                    case R.id.completed:
                        mPresenter.setFiltering(TasksFilterType.COMPLETED_TASKS);
                        break;
                    default:
                        mPresenter.setFiltering(TasksFilterType.ALL_TASKS);
                        break;
                
                mPresenter.loadTasks(false);
                return true;
            
        );

        popup.show();
    
    ............    

接下来看看TasksPresenter的代码:

public class TasksPresenter implements TasksContract.Presenter 
    ............
    //保留的View也是接口类型
    private final TasksContract.View mTasksView;
    ...........
    //从上文的代码,我们知道tasksView实际上就是Fragment
    public TasksPresenter(@NonNull TasksRepository tasksRepository,
            @NonNull TasksContract.View tasksView) 
        mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null");

        //Presenter持有View
        mTasksView = checkNotNull(tasksView, "tasksView cannot be null!");

        //View持有Fragment
        mTasksView.setPresenter(this);
    

    //Presenter完成实际的逻辑,与Model交互
    @Override
    public void start() 
        loadTasks(false);
    

    //结果交由View来显示
    @Override
    public void result(int requestCode, int resultCode) 
        // If a task was successfully added, show snackbar
        if (AddEditTaskActivity.REQUEST_ADD_TASK == requestCode
                && Activity.RESULT_OK == resultCode) 
            mTasksView.showSuccessfullySavedMessage();
        
    
    .................

最后来看看TasksContract中定义的接口:

//TaskContract内统一约定了View和Presenter的接口
public interface TasksContract 
    //View的接口主要与展示有关
    interface View extends BaseView<Presenter> 
        void setLoadingIndicator(boolean active);

        void showTasks(List<Task> tasks);
        ....................
    

    //Presenter接口主要与功能逻辑有关
    interface Presenter extends BasePresenter 
         void result(int requestCode, int resultCode);

        void loadTasks(boolean forceUpdate);

        void addNewTask();
        .........
    

我们来看看Google自己提供的MVP架构图:

四、总结
MVP实际上没有任何神秘可言,从设计的角度来看,
实际上就是为了保持类的功能单一,并且面向接口编程。

以上是关于Android中的MVP模式的主要内容,如果未能解决你的问题,请参考以下文章

Android:安卓学习笔记之MVP模式的简单理解和使用

Android:安卓学习笔记之MVP模式的简单理解和使用

Android:安卓学习笔记之MVP模式的简单理解和使用

MVP模式在Android开发中的应用

markdown Android中MVP中的存储库模式

Android中的MVP模式