詳談Android之MVP開發(fā)模式

****前言****
以前在寫Web項(xiàng)目的時(shí)候,也許沒(méi)有過(guò)多的考慮項(xiàng)目的開發(fā)模式,然而習(xí)慣了采用MVC的模式去開發(fā)項(xiàng)目,然而最近開發(fā)Android項(xiàng)目的時(shí)候,總是感覺(jué)View和Model聯(lián)系很緊密,從邏輯上基本不能分離出來(lái),然后就了解到了MVP模式,這種模式View層與Model層完全分離的,從而減輕了Activity的負(fù)擔(dān)。


  • MVP模式的簡(jiǎn)介
    MVP開發(fā)模式是從經(jīng)典的MVC模式演變過(guò)來(lái)的,其基本思路都是相通的。簡(jiǎn)單來(lái)說(shuō):MVP模式是基于MVC模式的。
    ****M是Model層,提供業(yè)務(wù)數(shù)據(jù)****
    ****V是View視圖,顯示數(shù)據(jù)****
    ****P是Presenter控制者,進(jìn)行邏輯處理****

  • MVP模式與MVC模式的區(qū)別
Paste_Image.png

從圖中可以清晰地看出:它們有一個(gè)比較明顯的區(qū)別就是,MVC中是允許Model和View進(jìn)行交互的;而MVP中很明顯,Model與View之間的交互由Presenter完成,并且Presenter與View之間的交互是通過(guò)接口的,換句話說(shuō):在MVP中View并不直接使用Model,它們之間的通信是通過(guò)Presenter來(lái)進(jìn)行的,所有的交互都發(fā)生在Presenter內(nèi)部。


  • MVP模式的優(yōu)缺點(diǎn)
    優(yōu)點(diǎn):降低耦合,代碼靈,層級(jí)職責(zé)更明顯,易于單元測(cè)試
    缺點(diǎn):造成類數(shù)量爆炸,代碼復(fù)雜度和學(xué)習(xí)成本高,在某些場(chǎng)景下presenter的復(fù)用會(huì)產(chǎn)生接口冗余
    入門的體驗(yàn):給一個(gè)demo你看的話,你會(huì)發(fā)現(xiàn)MVP模式開發(fā)的思路很清晰,但是你會(huì)發(fā)覺(jué)項(xiàng)目會(huì)產(chǎn)生很多的類,代碼的復(fù)雜度會(huì)高些。網(wǎng)上常說(shuō):雖然mvp基于mvc,但是由于類太多未必可以寫的出來(lái)。

  • MVP的小實(shí)戰(zhàn)DEMO
    不想寫太多理論性的文筆,接下來(lái)講解demo的編程思路【代碼展示-用戶登陸】
    ****demo的項(xiàng)目結(jié)構(gòu)****
Paste_Image.png

****Bean**** UserBean毋庸置疑這個(gè)必須有的,和mvc一樣

package com.samego.alic.demomvp.bean;

/**
 * UserBean
 * Created by alic on 16-4-13.
 */
public class User {
    private String username;//用戶名
    private String password;//密碼

    //construct
    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    //set and get start
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
    //set and get end
}


****Model**** 從業(yè)務(wù)上思考,User至少有l(wèi)ogin()該方法

package com.samego.alic.demomvp.model;

import com.samego.alic.demomvp.presenter.OnLoginListener;

/**
 *UserModel接口
 * Created by alic on 16-4-13.
 */
public interface UserModel {
    /**
     * 用戶登陸
     * @param username 用戶名
     * @param password 密碼
     * @param onLoginListener 登陸結(jié)果監(jiān)聽(tīng)是否登陸成功
     */
    void login(String username,String password,OnLoginListener onLoginListener);
}
package com.samego.alic.demomvp.model;

/**
 *UserModelImpl類實(shí)現(xiàn)UserModel接口
 * Created by alic on 16-4-13.
 */
public class UserModelImpl implements UserModel {

    @Override
    public void login(final String username, final String password, final OnLoginListener loginListener) {
        new Thread(){
            @Override
            public void run() {
                try {
                    //模擬網(wǎng)絡(luò)數(shù)據(jù)交互等待時(shí)間
                    Thread.sleep(2000);
                    //模擬登陸成功
                    if("alic".equals(username)&&"123456".equals(password)){
                        User user = new User(username,password);
                        loginListener.loginSuccess(user);
                        //模擬登陸失敗
                    }else {
                        loginListener.loginFailed();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}
package com.samego.alic.demomvp.model;

/**
 *登陸監(jiān)聽(tīng)接口
 * Created by alic on 16-4-13.
 */
public interface OnLoginListener {
    /**
     * 用戶登陸成功
     * @param user UserBean
     */
    void loginSuccess(User user);

    /**
     * 用戶登陸失敗
     */
    void loginFailed();
}

****View**** 難點(diǎn)就是在View這里,View該有哪些方法,因?yàn)镻resenter與View交互是通過(guò)接口。
簡(jiǎn)單分析該接口應(yīng)該有哪些方法,****其實(shí)這些方法就是輔助Presenter的邏輯而存在的****

//獲取用戶名 密碼
String getUsername();
String getPassword();
//清空用戶名 密碼
void clearUsername();
void clearPassword();
//顯示 隱藏加載
void showLoading();
void hideLoading();
//跳轉(zhuǎn)主界面
void toMainActivity(User user);~~~

//顯示錯(cuò)誤
void showFailed();

Summary

package com.samego.alic.demomvp.view;

import com.samego.alic.demomvp.bean.User;

/**
*用戶登錄輔助視圖view 雖然由activity顯示,目的就是輔助Presenter

  • Created by alic on 16-4-13.
    */
    public interface UserLoginView {
    //獲取用戶名 密碼
    String getUsername();
    String getPassword();

    //清空用戶名 密碼
    void clearUsername();
    void clearPassword();

    //顯示 隱藏加載
    void showLoading();
    void hideLoading();

    //跳轉(zhuǎn)主界面
    void toMainActivity(User user);

    //顯示錯(cuò)誤
    void showFailed();
    }

package com.samego.alic.demomvp.view;

/**
*用戶登陸界面主視圖view
*Created by alic on 16-4-13.
*/
public class LoginActivity extends AppCompatActivity implements UserLoginView, View.OnClickListener {
private EditText username,password;
private Button login,reset;
private ProgressBar loginLoading;
private UserLoginPresenter loginPresenter = new UserLoginPresenter(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
StatusBarCompat.setStatusBarColor(this,StatusBarCompat.COLOR_ToolBar_HIGHTBLUE);
//初始化
initViews();
}

/**
 * 初始化視圖組件
 */
public void initViews(){
    username = (EditText) findViewById(R.id.login_username);
    password = (EditText) findViewById(R.id.login_password);
    login = (Button) findViewById(R.id.login_button);
    reset = (Button) findViewById(R.id.reset_button);
    loginLoading = (ProgressBar) findViewById(R.id.login_loading);
    loginLoading.setVisibility(View.INVISIBLE);

    login.setOnClickListener(this);
    reset.setOnClickListener(this);
}

@Override
public String getUsername() {
    return username.getText().toString();
}

@Override
public String getPassword() {
    return password.getText().toString();
}

@Override
public void clearUsername() {
    username.setText("");
}

@Override
public void clearPassword() {
    password.setText("");
}

@Override
public void showLoading() {
    loginLoading.setVisibility(View.VISIBLE);
}

@Override
public void hideLoading() {
    loginLoading.setVisibility(View.INVISIBLE);
}

@Override
public void toMainActivity(User user) {

// Intent intent = new Intent(LoginActivity.this,MainActivity.class);
// startActivity(intent);
Toast.makeText(this,"登陸成功",Toast.LENGTH_SHORT).show();

}

@Override
public void showFailed() {
    Toast.makeText(this,"用戶名或密碼錯(cuò)誤",Toast.LENGTH_SHORT).show();
}

@Override
public void onClick(View v) {
    switch (v.getId()){
        case R.id.login_button:
            loginPresenter.login();
            break;
        case R.id.reset_button:
            loginPresenter.clear();
            break;
        default:
            break;
    }
}

}

****Presenter****  Presenter是用作Model和View之間交互的橋梁,該方法也應(yīng)該有哪些方法呢,****這些方法其實(shí)就是我們?cè)诮缑嫔纤吹降倪壿嬏幚?***,比如login()以及reset()

package com.samego.alic.demomvp.presenter;

/**
*UserLoginPresenter

  • Presenter負(fù)責(zé)完成UserLoginView層與UserModel層的交互

  • Created by alic on 16-4-13.
    */
    public class UserLoginPresenter {
    private UserModel userModel;
    private UserLoginView userLoginView;
    private Handler handler = new Handler();

    //construct
    public UserLoginPresenter(UserLoginView userLoginView) {
    this.userLoginView = userLoginView;
    userModel = new UserModelImpl();
    }

    /**

    • 登陸function
      */
      public void login(){
      userLoginView.showLoading();
      userModel.login(userLoginView.getUsername(), userLoginView.getPassword(), new OnLoginListener() {
      @Override
      public void loginSuccess(final User user) {
      handler.post(new Runnable() {
      @Override
      public void run() {
      userLoginView.toMainActivity(user);
      userLoginView.hideLoading();
      }
      });
      }

       @Override
       public void loginFailed() {
           handler.post(new Runnable() {
               @Override
               public void run() {
                   userLoginView.showFailed();
                   userLoginView.hideLoading();
               }
           });
       }
      

      });
      }

    /**

    • 清空f(shuō)unction
      */
      public void clear(){
      userLoginView.clearUsername();
      userLoginView.clearPassword();
      }
      }

以上就是一個(gè)非常精簡(jiǎn)又經(jīng)典的Demo,對(duì)于有些不了解的或者不對(duì)的地方歡迎交談,THX!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,323評(píng)論 25 708
  • 轉(zhuǎn)載至:http://m.itdecent.cn/p/9a6845b26856 “Android MVP 詳解...
    SnowDragonYY閱讀 10,421評(píng)論 5 241
  • 作者:李旺成 時(shí)間:2016年4月3日 “Android MVP 詳解(下)”已經(jīng)發(fā)布,歡迎大家提建議。 MVP ...
    diygreen閱讀 129,361評(píng)論 85 1,320
  • 兜, 我很高興又能與你一起晨練,一起打羽毛球。都說(shuō)早起的鳥兒有蟲吃,我吃到享受晨光的快樂(lè),吃到了與你一起欣賞羽毛球...
    蔡新花閱讀 177評(píng)論 0 5
  • LancyLuna閱讀 190評(píng)論 0 0

友情鏈接更多精彩內(nèi)容