android中MVP模式(一)

presenter 主持人。主导器

======

1. 明确需求,界面如下:可存,可根据id读取数据。

包结构图

2. 建立bean
[java] view plain copy
 
 print?
  1. public class UserBean {  
  2.      private String mFirstName;  
  3.      private String mLastName;  
  4.   
  5.      public UserBean(String firstName, String lastName) {  
  6.             this. mFirstName = firstName;  
  7.             this. mLastName = lastName;  
  8.      }  
  9.   
  10.      public String getFirstName() {  
  11.             return mFirstName;  
  12.      }  
  13.   
  14.      public String getLastName() {  
  15.             return mLastName;  
  16.      }  
  17. }  
3. 建立model(处理业务逻辑,这里指数据读写),先写接口,后写实现
[java] view plain copy
 
 print?
  1. public interface IUserModel {  
  2.      void setID(int id);  
  3.   
  4.      void setFirstName(String firstName);  
  5.   
  6.      void setLastName(String lastName);  
  7.   
  8.      int getID();  
  9.   
  10.      UserBean load(int id);// 通过id读取user信息,返回一个UserBean  
  11. }  
实现不在这里写了。
4. 建立view(更新ui中的view状态),这里列出需要操作当前view的方法,也是接口
[java] view plain copy
 
 print?
  1. public interface IUserView {  
  2.      int getID();  
  3.   
  4.      String getFristName();  
  5.   
  6.      String getLastName();  
  7.   
  8.      void setFirstName(String firstName);  
  9.   
  10.      void setLastName(String lastName);  
  11. }  
5. 建立presenter(主导器,通过iView和iModel接口操作model和view),activity可以把所有逻辑给presenter处理,这样java逻辑就从手机的activity中分离出来。
[java] view plain copy
 
 print?
  1. public class UserPresenter {  
  2.      private IUserView mUserView;  
  3.      private IUserModel mUserModel;  
  4.   
  5.      public UserPresenter(IUserView view) {  
  6.             mUserView = view;  
  7.             mUserModel = new UserModel();  
  8.      }  
  9.   
  10.      public void saveUser( int id, String firstName, String lastName) {  
  11.             mUserModel.setID(id);  
  12.             mUserModel.setFirstName(firstName);  
  13.             mUserModel.setLastName(lastName);  
  14.      }  
  15.   
  16.      public void loadUser( int id) {  
  17.            UserBean user = mUserModel.load(id);  
  18.             mUserView.setFirstName(user.getFirstName()); // 通过调用IUserView的方法来更新显示  
  19.             mUserView.setLastName(user.getLastName());  
  20.      }  
  21. }  
6. activity中实现iview接口,在其中操作view,实例化一个presenter变量。
[java] view plain copy
 
 print?
  1. public class MainActivity extends Activity implements OnClickListener,IUserView {  
  2.   
  3.      UserPresenter presenter;  
  4.      EditText id,first,last;  
  5.      @Override  
  6.      protected void onCreate(Bundle savedInstanceState) {  
  7.             super.onCreate(savedInstanceState);  
  8.            setContentView(R.layout. activity_main);  
  9.              
  10.            findViewById(R.id. save).setOnClickListener( this);  
  11.            findViewById(R.id. load).setOnClickListener( this);  
  12.             id = (EditText) findViewById(R.id. id);  
  13.             first = (EditText) findViewById(R.id. first);  
  14.             last = (EditText) findViewById(R.id. last);  
  15.              
  16.             presenter = new UserPresenter( this);  
  17.      }  
  18.   
  19.      @Override  
  20.      public void onClick(View v) {  
  21.             switch (v.getId()) {  
  22.             case R.id. save:  
  23.                  presenter.saveUser(getID(), getFristName(), getLastName());  
  24.                  break;  
  25.             case R.id. load:  
  26.                  presenter.loadUser(getID());  
  27.                  break;  
  28.             default:  
  29.                  break;  
  30.            }  
  31.      }  
  32.   
  33.      @Override  
  34.      public int getID() {  
  35.             return new Integer( id.getText().toString());  
  36.      }  
  37.   
  38.      @Override  
  39.      public String getFristName() {  
  40.             return first.getText().toString();  
  41.      }  
  42.   
  43.      @Override  
  44.      public String getLastName() {  
  45.             return last.getText().toString();  
  46.      }  
  47.   
  48.      @Override  
  49.      public void setFirstName(String firstName) {  
  50.             first.setText(firstName);  
  51.      }  
  52.   
  53.      @Override  
  54.      public void setLastName(String lastName) {  
  55.             last.setText(lastName);  
  56.      }  
  57.   
  58. }  
7. 所谓的mvp,即是(model-处理业务逻辑(主要是数据读写,或者与后台通信(其实也是读写数据)),view-处理ui控件,presenter-主导器,操作model和view)
------------
1. 需求,这个是《android开发必知的50个诀窍》一书中的mvp章节的需求。
在splash页面中,判断是否有网络连接,有则跳到下个页面,无则弹出一条消息通知用户,同时在检查网络是否正常的期间显示一个进度条。
 

2. 类目录结构

[java] view plain copy
 
 print?
  1. 3. model接口和实现  
  2. public interface INetConnect {  
  3.      boolean isNetConnect( Context context);  
  4. }  
  5. public class NetConnect implements INetConnect {  
  6.   
  7.      @Override  
  8.      public boolean isNetConnect(Context context) {  
  9.             if (context != null) {  
  10.                 ConnectivityManager mConnectivityManager = (ConnectivityManager) context  
  11.                           .getSystemService(Context. CONNECTIVITY_SERVICE);  
  12.                 NetworkInfo mNetworkInfo = mConnectivityManager  
  13.                            .getActiveNetworkInfo();  
  14.                  if (mNetworkInfo != null) {  
  15.                       return mNetworkInfo.isAvailable();  
  16.                 }  
  17.            }  
  18.             return false;  
  19.      }  
  20.   
  21. }  
  22.   
  23. 4. view接口  
  24. public interface ISplashView {  
  25.      void showProcessBar();  
  26.      void hideProcessBar();  
  27.      void showNetError();  
  28.      void startNextActivity();  
  29. }  
  30.   
  31. 5. presenter实现  
  32. public class SplashPresenter {  
  33.      private INetConnect connect;  
  34.      private ISplashView iView;  
  35.        
  36.      public SplashPresenter(ISplashView iView){  
  37.             this. iView = iView;  
  38.             connect = new NetConnect();  
  39.      }  
  40.        
  41.      public void didFinishLoading(Context context){  
  42.             iView.showProcessBar();  
  43.             if( connect.isNetConnect(context)){  
  44.                  iView.startNextActivity();  
  45.            } else{  
  46.                  iView.showNetError();  
  47.            }  
  48.             iView.hideProcessBar();  
  49.      }  
  50. }  
  51.   
  52. 6.activity中代码  
  53. public class MainActivity extends Activity implements ISplashView{  
  54.   
  55.      SplashPresenter presenter;  
  56.      private ProgressDialog progressBar;  
  57.      @Override  
  58.      protected void onCreate(Bundle savedInstanceState) {  
  59.             super.onCreate(savedInstanceState);  
  60.            setContentView(R.layout. activity_main);  
  61.              
  62.             presenter = new SplashPresenter( this);  
  63.      }  
  64.   
  65.      @Override  
  66.      protected void onResume() {  
  67.             super.onResume();  
  68.             presenter.didFinishLoading( this);  
  69.      }  
  70.        
  71.      @Override  
  72.      public void showProcessBar() {  
  73.             if ( progressBar == null) {  
  74.                  progressBar = new ProgressDialog( this);  
  75.                  progressBar.setCancelable( true);  
  76.                  progressBar.setCanceledOnTouchOutside( true);  
  77.                  progressBar.setMessage( "更新数据中,请稍后" );  
  78.            }  
  79.             progressBar.show();  
  80.      }  
  81.   
  82.      @Override  
  83.      public void hideProcessBar() {  
  84.             progressBar.hide();  
  85.      }  
  86.   
  87.      @Override  
  88.      public void showNetError() {  
  89.            Toast. makeText(this, "暂无网络", Toast.LENGTH_SHORT).show();  
  90.      }  
  91.   
  92.      @Override  
  93.      public void startNextActivity() {  
  94.            Toast. makeText(this, "跳到下个activity", Toast.LENGTH_SHORT).show();  
  95.      }  
  96.   

==========

MVP模式简单实例

一个简单的登录界面(实在想不到别的了╮( ̄▽ ̄")╭),点击LOGIN则进行账号密码验证,点击CLEAR则重置输入。

项目结构看起来像是这个样子的,MVP的分层还是很清晰的。我的习惯是先按模块分Package,在模块下面再去创建model、view、presenter的子Package,当然也可以用model、view、presenter作为顶级的Package,然后把所有的模块的model、view、presenter类都到这三个顶级Package中,就好像有人喜欢把项目里所有的Activity、Fragment、Adapter都放在一起一样。

首先来看看LoginActivity

public class LoginActivity extends ActionBarActivity implements ILoginView, View.OnClickListener {

    private EditText editUser;
    private EditText editPass;
    private Button   btnLogin;
    private Button   btnClear;
    ILoginPresenter loginPresenter;
    private ProgressBar progressBar;

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

        //find view
        editUser = (EditText) this.findViewById(R.id.et_login_username);
        editPass = (EditText) this.findViewById(R.id.et_login_password);
        btnLogin = (Button) this.findViewById(R.id.btn_login_login);
        btnClear = (Button) this.findViewById(R.id.btn_login_clear);
        progressBar = (ProgressBar) this.findViewById(R.id.progress_login);

        //set listener
        btnLogin.setOnClickListener(this);
        btnClear.setOnClickListener(this);

        //init
        loginPresenter = new LoginPresenterCompl(this);
        loginPresenter.setProgressBarVisiblity(View.INVISIBLE);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_login_clear:
                loginPresenter.clear();
                break;
            case R.id.btn_login_login:
                loginPresenter.setProgressBarVisiblity(View.VISIBLE);
                btnLogin.setEnabled(false);
                btnClear.setEnabled(false);
                loginPresenter.doLogin(editUser.getText().toString(), editPass.getText().toString());
                break;
        }
    }

    @Override
    public void onClearText() {
        editUser.setText("");
        editPass.setText("");
    }

    @Override
    public void onLoginResult(Boolean result, int code) {
        loginPresenter.setProgressBarVisiblity(View.INVISIBLE);
        btnLogin.setEnabled(true);
        btnClear.setEnabled(true);
        if (result){
            Toast.makeText(this,"Login Success",Toast.LENGTH_SHORT).show();
            startActivity(new Intent(this, HomeActivity.class));
        }
        else
            Toast.makeText(this,"Login Fail, code = " + code,Toast.LENGTH_SHORT).show();
    }


    @Override
    public void onSetProgressBarVisibility(int visibility) {
        progressBar.setVisibility(visibility);
    }
}

从代码可以看出LoginActivity只做了findView以及setListener的工作,而且包含了一个ILoginPresenter,所有业务逻辑都是通过调用ILoginPresenter的具体接口来完成。所以LoginActivity的代码看起来很舒爽,甚至有点愉♂悦呢 (/ω\*)。视力不错的你可能还看到了ILoginView接口的实现,如果不懂为什么要这样写的话,可以先往下看,这里只要记住LoginActivity实现了ILoginView接口

再来看看ILoginPresenter

public interface ILoginPresenter {
    void clear();
    void doLogin(String name, String passwd);
    void setProgressBarVisiblity(int visiblity);
}
public class LoginPresenterCompl implements ILoginPresenter {
    ILoginView iLoginView;
    IUser user;
    Handler    handler;

    public LoginPresenterCompl(ILoginView iLoginView) {
        this.iLoginView = iLoginView;
        initUser();
        handler = new Handler(Looper.getMainLooper());
    }

    @Override
    public void clear() {
        iLoginView.onClearText();
    }

    @Override
    public void doLogin(String name, String passwd) {
        Boolean isLoginSuccess = true;
        final int code = user.checkUserValidity(name,passwd);
        if (code!=0) isLoginSuccess = false;
        final Boolean result = isLoginSuccess;
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                iLoginView.onLoginResult(result, code);
            }
        }, 3000);

    }

    @Override
    public void setProgressBarVisiblity(int visiblity){
        iLoginView.onSetProgressBarVisibility(visiblity);
    }

    private void initUser(){
        user = new UserModel("mvp","mvp");
    }
}

从代码可以看出,LoginPresenterCompl保留了ILoginView的引用,因此在LoginPresenterCompl里就可以直接进行UI操作了,而不用在Activity里完成。这里使用了ILoginView引用,而不是直接使用Activity,这样一来,如果在别的Activity里也需要用到相同的业务逻辑,就可以直接复用LoginPresenterCompl类了(一个Activity可以包含一个以上的Presenter,总之,需要什么业务就new什么样的Presenter,是不是很灵活(@ ̄︶ ̄@)),这也是MVP的核心思想

通过IVIew和IPresenter,把Activity的UI LogicBusiness Logic分离开来,Activity just does its basic job! 至于Model嘛,还是原来MVC里的Model。

再来看看ILoginView,至于ILoginView的实现类呢,翻到上面看看LoginActivity吧

public interface ILoginView {
    public void onClearText();
    public void onLoginResult(Boolean result, int code);
    public void onSetProgressBarVisibility(int visibility);
}

代码这种东西放在日志里讲好像除了把整个版面拉长没什么卵用,我把几种自己常用的MVP的写法写成一个Demo项目,欢迎围观和PullRequest:Android-MVP-Pattern

==========

原文地址:https://www.cnblogs.com/yue31313/p/7488801.html