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

Posted JMW1407

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android:安卓学习笔记之MVCMVP模式的简单理解和使用相关的知识,希望对你有一定的参考价值。

MVC、MVP

MVC模式的出现

  • 为解决程序模块化问题,于是MVC模式出现了:将业务逻辑数据处理界面显示进行分离来组织代码,即分成M、V、C层;

MVP模式的出现

  • 但M、V层还是有相互交叉、隔离度不够,同时写到Activity上使得Activity代码臃肿,于是出现了MVP: 隔离了MVC中的 M 与V 的直接联系,将M、V层更加隔离开来,并释放了Activity的压力;

1、为什么要进行技术框架的设计

1、模块化功能

  • 使得程序模块化,即:内部的高聚合、模块之间的低耦合

2、提高开发效率

  • 开发人员只需专注于某一点(视图显示、业务逻辑 / 数据处理)

3、提高测试效率

  • 方便后续的测试 & 定位问题

2、MVC模式

2.1、参数说明

  • Model:代表我们的数据模型,管理数据状态。
  • View:视图,即呈现给用户的UI,比如我们的layout.xml文件及Activity。
  • Controller:控制者,负责处理用户与app之间的交互,包含业务逻辑。所以是Model与View的中介,比如我们的Activity/Fragment。

2.2、模式说明


该模式存在的问题:Activity责任不明、十分臃肿

  • Activity由于其生命周期的功能,除了担任View层的部分职责(加载应用的布局、接受用户操作),还要承担Controller层的职责(业务逻辑的处理)
  • 随着界面的增多 & 逻辑复杂度提高,Activity类的代码量不断增加,越加臃肿

3、MVP模式

为了解决上述MVC模式存在的问题,把分离Activity中的View层Controller层的职责,从而对Activity代码量进行优化、瘦身,所以出现了MVP模式

3.1、参数说明

核心思想

把Activity里的逻辑都抽离到View和Presenter接口中去 & 由具体的实现类来完成。具体实现思路如下:

  • 把Activity中的UI逻辑抽象成View接口 & 由具体的实现类来完成
  • 把业务逻辑抽象成Presenter接口 & 由具体的实现类来完成
  • Model类还是原来MVC模式的Model层

3.2、模式说明


优点:(对比MVC模式)

  • 耦合度更低:通过Presenter实现数据和视图之间的交互,完全隔离了View层与Mode层,二者互不干涉
  • 避免了View、Model的直接联系,又通过Presenter实现两者之间的沟通

Activity代码变得更加简洁:简化了Activity的职责,仅负责UI相关操作,其余复杂的逻辑代码提取到了Presenter层中进行处理

3.3、实现步骤


通过UML图可看出,使用MVP模式的步骤如下:

本节通过一个 英语词典app实例 讲解 MVP模式具体的实现

  • MVP技术架构的项目结构非常清晰:把M、V、P层分别分为三个文件夹:Model、View、Presenter,每个文件下分别是对应的接口和实现的类
  • 其中Model层的fanyi类是作为实现用GSON解析JSON信息的一个JavaBean

步骤1:设置View层(IView接口 & 实现类)

/**
  * View接口:IfanyiView
  * 需定义在实现类中需要用到的方法
  */

  public interface IfanyiView     

    void init();//初始化   
    void SetInfo(String str); //输出翻译信息    
    void SetError(); //输出出错信息

    

/**
  * View实现类:MainActivity类
  * 注:由于MainActivity是对应View层的实现类,所以要实现View层的接口
  */

  public class MainActivity extends AppCompatActivity implements IfanyiView    

      private EditText et;    
      private TextView tv;    
      CidianPresenter cidianPresenter;  // 声明了Presenter对应类 

        @Override    
        protected void onCreate(Bundle savedInstanceState)  
               super.onCreate(savedInstanceState); 
               setContentView(R.layout.activity_main);        
                  // 实例化P对应类的对象和findView        
                   init();        
                // 接受用户的输入  
                findViewById(R.id.btnfanyi).setOnClickListener(new View.OnClickListener()       
              
                    @Override            
                    public void onClick(View v)                 
                    //将View层获得的数据传入Presenter层 ,注意还要传递MainActivity
                          cidianPresenter.InputToModel(et.getText().toString(), MainActivity.this);            
                                 
                      );    
                        

                    @Override    
                    public void init()        
                    //实例化P类的对象和findView        
                      cidianPresenter = new CidianPresenter(this);        
                      et = (EditText) findViewById(R.id.editText);        
                      tv = (TextView) findViewById(R.id.tv);    
                    

                    @Override  
                    //输出出错信息   
                    public void SetError()         
                      tv.setText("查询不成功,请检查网络");    
                     

                    //输出翻译信息
                    @Override    
                    public void SetInfo(String str)        
                    tv.setText(str);    
                     
                    

  // 从上述代码可看出,MainActivity只做了FindView、setListener的工作(包含了cidianPresenter),简洁清爽!

步骤2:设置Presenter层(创建IPresenter接口&实现类)

/**
  * Presenter接口:ICidianPresenter
  * 需定义在实现类中需要用到的方法
  */

  public interface ICidianPresenter     
      
     void InputToModel(String input,Context context); // 将View层获得的数据传入Model层

  


/**
  * Presenter层的实现类:CidianPresenter类
  * 注:由于CidianPresenter是对应Presenter层的实现类,所以要实现Presenter层的接口
  */

  public class CidianPresenter implements onfanyiListener,ICidianPresenter     
      // 1. 声明View层对应接口、Model层对应的类    
      IfanyiView fyV;    
      fanyimodel fanyimodel;    

      // 2. 重构函数,初始化View接口实例、Model实例    
      public  CidianPresenter(IfanyiView fyV)        
          this.fyV = fyV;        
          fanyimodel = new fanyimodel();   
         

      // 3.将View层获得的数据传入Model层,注意要传递this.当前类
          @Override    
          public void InputToModel(String input, Context context)  

          fanyimodel.HandleData(input, context, this);    

              
          // 回调函数,调用UI更新  
          @Override    
          public void onSuccess(String str)         
              fyV.SetInfo(str);      
          // 回调函数,调用UI输出出错信息
          @Override    
          public void onError()         
              fyV.SetError();     
          
 
      // 注:
      // a. 保留IfanyiView的引用,就可直接在CidianPresenter当前类进行UI操作而不用在Activity操作
      // b. 保留了Model层的引用就可以将View层的数据传递到Model层

步骤3:Model层(Model层接口 & 实现类)

/**
  * Model层接口:Ifanyi
  * 需定义在实现类中需要用到的方法
  */
  public interface Ifanyi   

    void HandleData(String input,Context context,final onfanyiListener listener);    
    String fanyiToString(fanyi fy);

  

/**
  * Model层的实现类:fanyiModel类
  * 注:由于fanyiModel是对应Model层的实现类,所以要实现Model层的接口
  */

  public class fanyimodel implements Ifanyi 

      private fanyi fy = new fanyi();

      public void HandleData(String input,Context context,final onfanyiListener listener)

          // 使用Volley框架来实现异步从网络的有道API获取翻译数据
          RequestQueue mQueue = Volley.newRequestQueue(context);
          StringRequest stringRequest = new StringRequest("http://fanyi.youdao.com/openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q="+input, new Response.Listener<String>() 
              @Override
              public void onResponse(String s) 

                  // 用Gson方式解析获得的json字符串
                  Gson gson = new Gson();
                  fy = gson.fromJson(s.trim(),fy.getClass());

                  // 回调监听器的函数把处理数据后的结果(翻译结果)返回给Presenter层
                  listener.onSuccess(fanyiToString(fy));
              
          , new Response.ErrorListener() 
              @Override
              public void onErrorResponse(VolleyError volleyError) 
                  listener.onError();
              
          );
          mQueue.add(stringRequest);
      

      public String fanyiToString(fanyi fy)
          // 处理解析后的json数据,转成UI输出的字符串
          String strexplain = "解释:";
          String strphonetic = "发音:";
          String strweb = "网络释义:";
          if (fy.basic == null)return "你所查找的还没有准确翻译";
          for (int i = 0; i<fy.basic.explains.length; i++)
              strexplain +=fy.basic.explains[i]+"\\n";
              if (i != fy.basic.explains.length-1 )
              strexplain +="\\t\\t\\t\\t";
          
          strphonetic += fy.basic.phonetic +"\\n";
          for (int i = 0; i<fy.web.size(); i++)
              for(int j = 0; j<fy.web.get(i).value.length;j++)
              
                  strweb += fy.web.get(i).value[j]+",";
              
              strweb += fy.web.get(i).key+"\\n";
              strweb += "\\t\\t\\t\\t\\t\\t\\t";
          
          return strexplain+"\\n"+strphonetic+"\\n"+strweb;
      
  

4、MVC、MVP模式的区别

在 MVC 框架中,请求流程如下:

View接受用户的请求
View传递请求给Controller
Controller操作Model进行数据更新
Model通知View变化
View根据更新的数据做出显示

而MVP框架中,请求流程如下:

View 接受用户请求
View 传递请求给Presenter
Presenter做逻辑处理,修改Model Model
通知Presenter数据变化
Presenter 更新View

5、实例分析

小明需要开发一个功能,当点击“find student id”按钮时,可以查询到他自己的学号。

5.1、MVC 实现

1、先实现一个 model,需要有通知View更新的能力,当model加载成功,如从db、获取后,需要告知View:

public class StudentModel 

    String mId;
    WelcomeActivity mActivity;

    public StudentModel (WelcomeActivity activity) 
        this.mActivity = activity;
    
    public void loadModel ()
        //search from db or intent
        mId = "1201030018";
        mActivity.updateUI(this);
    


2、Controller : 我们为了更好的理解MVC,将Activity进行了拆解。提取了一个简单的Controller

public class WelcomeController 

    WelcomeActivity mActivity;
    StudentModel mStudent;

    WelcomeController (WelcomeActivity activity) 
        this.mActivity = activity;
    

    public void loadData ()
        mStudent = new StudentModel(mActivity);
        mStudent.loadModel();
    

3、View : View需要发出点击事件,并且传递给Controller,同时需要根据Model更新UI:

public class WelcomeActivity extends AppCompatActivity 

    @Override
    protected void onCreate(Bundle savedInstanceState) 
       //省略
        final WelcomeController controller = new WelcomeController(this);
        mFindBtn.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                controller.loadData();
            
        );
    

    public void updateUI (StudentModel model) 
        mID.setText(model.mId);
    

调用链是:

View:OnClick -> Controller:loadData-> Model:loadModel-> View:updateUI

5.2、MVP实现

1、我们需要先对Model进行封装,当loadModel后,不直接通知View更新,而是通知监听方(Presenter):

public class StudentModel 
    String mId;
    OnGetListener mListener;

    public StudentModel (OnGetListener listener) 
        this.mListener = listener;
    
    public void loadModel ()
        //search from db or intent
        mId = "1201030018";
        if (mListener != null) 
            mListener.onSuccess(this);
        
    
    interface OnGetListener 
        void onSuccess (StudentModel student);
    

2、再定义Presenter ,接收到来自View的操作命令后,进行逻辑处理,处理Model,修改完成后 通知View进行修改。

public class WelcomePresenter 

    WelcomeActivity mActivity;
    StudentModel mStudent;

    WelcomePresenter (WelcomeActivity activity) 
        this.mActivity = activity;
    

    public void loadData ()
        mStudent = new StudentModel(new StudentModel.OnGetListener() 
            @Override
            public void onSuccess(StudentModel student) 
                mActivity.updateUI(student);
            
        );
    

3、对于View,操作方式只是修改了持有的对象 WelcomeController->WelcomePresenter,其他保持不变。

这时调用流程变成了:

View:OnClick ->
Presenter:loadData->
Model:loadModel->
Presenter:onSuccess>
View:updateUI

我们将View的数据更新 从Model->View,转变成了Presenter->View,解除了View和Model的耦合。

参考

1、https://www.jianshu.com/p/9a6845b26856
2、https://blog.csdn.net/vector_yi/article/details/24719873?utm_source=tuicool
3、https://www.cnblogs.com/JustRun1983/p/3679827.html
4、一文带你全面了解MVC、MVP、MVVM模式(含实例讲解)
5、Android中MVC/MVP模式区别
6、Android MVC,MVP和MVVM 思想&例子

以上是关于Android:安卓学习笔记之MVCMVP模式的简单理解和使用的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

Android :安卓第一行代码学习笔记之 解析JSON格式数据

Android :安卓学习笔记之事件内存泄露 的简单理解

Android:安卓学习笔记之共享元素的简单理解和使用