Android架构探究之MVP设计模式

Android架构探究之MVP设计模式


0. MVP是有MVC衍化而来的,不熟悉MVC的同学可以看这篇文章

Android架构探究之MVC设计模式: 点击阅读

1. MVP模式介绍-Model-View-Persenter

MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。[1]*


2. MVP与MVC的区别

MVP 流程图 Android架构探究之MVP设计模式
通过该流程图我们可以看出Presenter层作为与MVC相似的Controller层处于 View层和Model层中间的位置。
.
所以Presenter在MVP中担任了一个“桥梁”的作用,控制与接收分别来自View层和Model层的指令与状态,将View层和Model层隔离开来,起到了View层与Model层之间的解藕的作用,View和Model将不在有联系。
.
View层的UI更新交于Activity,业务交于Presenter层,数据处理还是在Model层
.
MVP这样做的好处自然是模块的职责划分更清晰,提高了代码的维护性。


3. 在Android中如何实现标准的MVP设计架构?

Android架构探究之MVP设计模式
  • 需求假设:
  • 2个EditView 分别可以输入 学生姓名,学生性别
  • 1个Button 按压下去后,将EditView输入的内容作为新学生添加,并实时自动刷新展示学生总人数。
  • 1个Button 按压下去后,手动刷新展示所有学生信息

Presenter层作为控制器和通信的桥梁,需同时持有V层和M层的对象,并只通过其对象实现的自身接口方法进行控制,不直接调用对象内定义的方法。
V层和M层自定义自己的接口并重写其接口内的方法,其接口内定义的方法作为向Presenter提供可以调用的方法。
.


  • 0. 项目结构 - gif 演示

Android架构探究之MVP设计模式.
Android架构探究之MVP设计模式

  • 1. Bean类,学生信息StudentBean

作为创建的学生对象

/**
 * 学生信息Bean
 */
public class StudentBean {
   private String name;
   private String gender;
   public StudentBean(String name, String gender){
      this.name = name;
      this.gender = gender;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }

   public String getGender() {
      return gender;
   }

   public void setGender(String gender) {
      this.gender = gender;
   }
}

  • 2. View层,Activity作为View层管理视图UI,且自定义接口并实现内部方法作为与P层数据事件传递的方法。

MainActivityView

public class MainActivityView extends AppCompatActivity implements MainActivityViewImpl {

    private EditText vEdtName, vEdtGender;
    private Button vBtnAdd,vBtnGetStudentInfo;
    private TextView vTvDisplay,vTvDisplayListNumber;
    //实例化StudentPresenter控制器
    private StudentPresenter mStudentPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        addClickListener();
    }

    private void initView() {
        mStudentPresenter = new StudentPresenter(this);
        vEdtName = findViewById(R.id.vEdtName);
        vEdtGender = findViewById(R.id.vEdtGender);
        vTvDisplay = findViewById(R.id.vTvDisplayStudentInfo);
        vBtnAdd = findViewById(R.id.vBtnAdd);
        vTvDisplayListNumber = findViewById(R.id.vTvDisplayListNumber);
        vBtnGetStudentInfo = findViewById(R.id.vBtnGetStudentInfo);
    }

    private void addClickListener(){
        vBtnAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mStudentPresenter.addStudent(); //响应用户点击按钮操作,通知Presenter做处理

            }
        });
        vBtnGetStudentInfo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mStudentPresenter.doRefreshListInfo();
            }
        });
    }

    @Override
    public String getStudentName() {
        return vEdtName.getText().toString().trim();
    }

    @Override
    public String getStudentGender() {
        return vEdtGender.getText().toString().trim();
    }

    @Override
    public void updateView_allStudentInfo(String string) {
        vTvDisplay.setText(string);
    }

    @Override
    public void updateView_studentNumber(String string) {
        vTvDisplayListNumber.setText(string);
    }

    //假如产品改需求,通过Toast弹窗的显示当前学生人数,
    //那么我们只需要在V层实现的自身接口改就行了。
//    @Override
//    public void updateView_studentNumber(String string) {
//        Toast.makeText(this,string,Toast.LENGTH_SHORT).show();
//    }

}

MainActivityViewImpl

/**
 * View层接口,在此定义并列出所有 V层 可以进行的操作
 */
public interface MainActivityViewImpl {
    /**
     * 获取学生姓名 (可以看作提供给 Presenter 调用的方法)
     */
    String getStudentName();
    /**
     * 获取学生性别 (可以看作提供给 Presenter 调用的方法)
     */
    String getStudentGender();
    /**
     * 手动更新View的UI-所有list学生信息
     */
    void updateView_allStudentInfo(String string);
    /**
     * 自动更新View的UI-学生List数量
     */
    void updateView_studentNumber(String string);
}

  • 3. Model层,处理数据,且自定义接口并实现内部方法作为与P层数据事件传递的方法。

StudentModel

/**
 * Model层,作为数据处理的层,通过实现StudentModelImpl里的方法,进行对应的数据操作
 */
public class StudentModel implements StudentModelImpl {
    private List <StudentBean> mStudentList = new ArrayList<>();
    /**
     * 向P层提供方法,对从Presenter拿到的 name 和 gender 作为数据进行处理,操作为创建一个新的学生bean并储存至学生list中
     * 处理完毕后,通过接口回调返回给P层状态
     * @param name
     * @param gender
     */
    @Override
    public void addStudent(String name, String gender, eventAddStudentCallBack studentCallBack) {
        StudentBean studentBean = new StudentBean(name,gender);
        mStudentList.add(studentBean);
        studentCallBack.completed(mStudentList.size()); //回调返回给P层
    }
    /**
     * 返回学生list
     */
    @Override
    public List getStudentList() {
        return mStudentList;
    }
}

StudentModelImpl

/**
 * Model层接口,在此定义并列出所有 M层 可以进行的操作
 */
public interface StudentModelImpl {

    /**
     * 添加学生操作 - 回调
     */
    interface eventAddStudentCallBack{
        void completed(int listSize);
    }

    /**
     * 添加学生操作,(可以看作提供给 Presenter 调用的方法)
     * @param name
     * @param gender
     * @param studentCallBack
     */
    void addStudent(String name, String gender,eventAddStudentCallBack studentCallBack);

    /**
     * 获取学生list,(可以看作提供给 Presenter 调用的方法)
     */
    List getStudentList();
}

  • 4. Presenter层,同时持有V层和M层的对象,通过V层和M层对象的接口内部方法实现双向通信事件传递。隔绝了V层和M层的直接通信

StudentModel


/**
 * Presenter控制器负责逻辑分发,在View层(Activity与xml)收到的用户的操作指令后,将起转发给Model层处理
 * Model层处理完毕后,返回结果到这里进行处理后,再告知View层进行UI更新。
 */
public class StudentPresenter{
    //Activity对象,同时V层实现了自身的接口
    private MainActivityView mainActivityView;
    //Model对象,同时M对象实现了自身的接口
    private StudentModel mStudentModel;
    public StudentPresenter(MainActivityView activity){
        mainActivityView = activity;
        mStudentModel = new StudentModel();
    }

    /**
     * 调用M层的接口对象,添加学生信息,并从回调结果更新V层的UI
     */
    public void addStudent(){
        String name = mainActivityView.getStudentName(); //从V层的接口方法获取输入的学生名字
        String gender = mainActivityView.getStudentGender(); //从V层的接口方法获取输入的学生性别
        //将数据 和 操作指令转发给M层做处理,M层处理结束后通过接口返回结果
        mStudentModel.addStudent(name, gender, new StudentModelImpl.eventAddStudentCallBack() {
            @Override
            public void completed(int listSize) {
                mainActivityView.updateView_studentNumber("当前人数: "+listSize);
            }
        });
    }

    /**
     * 调用V层的接口对象,更新V层的UI
     */
    public void doRefreshListInfo(){
        List<StudentBean> list  = mStudentModel.getStudentList();
        String text = "";
        for(int i=0; i<list.size(); i++){
            String studentInfo = "\n"+"姓名:"+list.get(i).getName() +" 性别: "+ list.get(i).getGender()+"\n";
            text = text + studentInfo;
        }
        mainActivityView.updateView_allStudentInfo(text);
    }

}


4. 完成代码请看github


5. Android技术生活交流

微信 ----- QQ


Android架构探究之MVP设计模式Android架构探究之MVP设计模式Android架构探究之MVP设计模式


[1]* 百度文献

上一篇:Linux中进程的退出


下一篇:第4期《return 0和 exit(0)的区别 》