Android开发模式之MVP

作者: cooperise | 来源:发表于2016-10-01 21:58 被阅读201次

    一、 什么是MVP

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

    二、MVP与MVC的区别

    作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller。

    MVC模式 MVP模式

    三、Android中的MVP

    代码案例:Login MVP

    • Model
    /**  模型层 ——— 登录接口  **/
    public interface ILoginModel {    
         void login(String username, String password, LoginCallBack callBack);
    }
    
    /**  模型层 ——— 完成具体的数据操作。  **/
    public class LoginModel implements ILoginModel {    
    
         @Override    
         public void login(String username, String password, LoginCallBack callBack) {        
            if (username.equals("MVP") && password.equals("MVP")){            
                callBack.onLoginSuccess();        
            }else{            
                callBack.onLoginFail();        
            }    
         }
    }
    
    • View
    /**  视图层 ——— 视图操作接口     **/
    public interface ILoginView {    
    
         void initView();   
    
         void onUsernameEmpty();   // 用户名为空时的显示操作    
         void onPasswordEmpty();   // 密码为空时的显示操作    
         void onLoginSuccess();   // 登陆成功时的显示操作    
         void onLoginFail();   // 密码失败时的显示操作
    }
    
    /**  视图层 ——— 只是作为接受用户数据和展示数据的方式     **/
    public class LoginView extends LinearLayout implements ILoginView, View.OnClickListener{  
      
         private Context context;    
         private EditText mUsername;    
         private EditText mPassword;    
         private Button mLoginBtn;    
    
         private ILoginPresenter presenter;
    
         public LoginView(Context context, AttributeSet attrs) {        
            super(context, attrs);        
            this.context = context;    
         }    
        
         @Override
         public void initView(){        
            mUsername = (EditText) findViewById(R.id.et_username);        
            mPassword = (EditText) findViewById(R.id.et_password);        
            mLoginBtn = (Button) findViewById(R.id.btn_login);    
    
            presenter = new LoginPresenter(this);
         }    
    
         @Override
         public void onClick(View v) {    
            switch (v.getId()){        
               case R.id.btn_login:            
                  presenter.login(mUsername.getText().toString(), 
                                  mPassword.getText().toString());            
                  break;    
             }
         }
    
         @Override
         public void onUsernameEmpty() {        
            Toast.makeText(context, "用户名不能为空", Toast.LENGTH_SHORT).show();    
         } 
    
         @Override
         public void onPasswordEmpty() {        
            Toast.makeText(context, "密码不能为空", Toast.LENGTH_SHORT).show();    
         }
    
         @Override
         public void onLoginSuccess() {        
            Toast.makeText(context, "登录成功", Toast.LENGTH_SHORT).show();    
         }
    
         @Override
         public void onLoginFail() {       
            Toast.makeText(context, "登录失败", Toast.LENGTH_SHORT).show();    
         }
    }
    
    • Presenter
    public interface ILoginPresenter {    
         void login(String username, String password);
    }
    
    public class LoginPresenter implements ILoginPresenter, LoginCallBack{
        
         private ILoginModel loginModel;    
         private ILoginView loginView;    
    
         public LoginPresenter(ILoginView loginView){        
            loginModel = new LoginModel();        
            this.loginView = loginView;    
         }    
    
         @Override    
         public void login(String username, String password) {        
            if (TextUtils.isEmpty(username)){            
                 loginView.onUsernameEmpty();        
            }else if (TextUtils.isEmpty(password)){            
                 loginView.onPasswordEmpty();        
            }else {            
                 loginModel.login(username, password, this);        
            }    
         }    
       
         @Override    
         public void onLoginSuccess() {        
            loginView.onLoginSuccess();    
         }   
      
         @Override    
         public void onLoginFail() {        
            loginView.onLoginFail();    
         }
    }
    
    • else
    /**  此时Activity就变为了承载视图层的容器。 **/
    public class MainActivity extends AppCompatActivity {    
    
         private LoginView loginview;    
    
         @Override    
         protected void onCreate(Bundle savedInstanceState) {        
            super.onCreate(savedInstanceState);        
            setContentView(R.layout.activity_main);        
            initPresenter();    
         }    
    
         private void initPresenter(){        
            loginview = (LoginView) findViewById(R.id.loginview);        
            loginview.initView(); 
         }
    }
    
    <!--  将LoginView作为父容器  -->
    <com.scnu.zhou.mvc.view.LoginView 
          xmlns:android="http://schemas.android.com/apk/res/android"    
          android:layout_width="match_parent"    
          android:layout_height="match_parent"    
          android:paddingBottom="@dimen/activity_vertical_margin"    
          android:paddingLeft="@dimen/activity_horizontal_margin"    
          android:paddingRight="@dimen/activity_horizontal_margin"    
          android:paddingTop="@dimen/activity_vertical_margin"    
          android:orientation="vertical"    
          android:id="@+id/loginview">    
    
          <EditText        
              android:id="@+id/et_username"        
              android:layout_width="match_parent"        
              android:layout_height="wrap_content"        
              android:inputType="text"/>    
    
          <EditText        
              android:id="@+id/et_password"        
              android:layout_width="match_parent"        
              android:layout_height="wrap_content"        
              android:layout_marginTop="10dp"        
              android:inputType="textPassword"/>    
    
          <Button        
              android:id="@+id/btn_login"        
              android:layout_width="match_parent"        
              android:layout_height="50dp"        
              android:text="Login"        
              android:layout_marginTop="10dp"/>
    </com.scnu.zhou.mvc.view.LoginView>
    

    三、 MVP模式的优缺点

    优点:

    1、模型与视图完全分离,我们可以修改视图而不影响模型
    2、可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部
    3、我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁。
    4、如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)

    缺点:

    由于对视图的渲染放在了Presenter中,所以视图和Presenter的交互会过于频繁。还有一点需要明白,如果Presenter过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密。一旦视图需要变更,那么Presenter也需要变更了。比如说,原本用来呈现Html的Presenter现在也需要用于呈现Pdf了,那么视图很有可能也需要变更。

    相关文章

      网友评论

        本文标题:Android开发模式之MVP

        本文链接:https://www.haomeiwen.com/subject/oszryttx.html