android中MVP或者說mvp模式的使用及思想分解,mvp和mvc的區別

1,首先,什麼是mvp模式?爲什麼使用mvp?


(官方描述:)

關於mvp模式,可以這樣認識他,隨着UI創建技術的功能日益增強,UI層(可以粗略理解爲activity頁面,如果你不理解的話)也履行着越來越多的職責。爲了更好地細分視圖(View)與模型(Model)的功能,讓View專注於處理數 據的可視化以及與用戶的交互,同時讓Model只關係數據的處理,基於MVC概念的MVP(Model-View-Presenter)模式應運而生。


在Android開發中,Activity並不是一個標準的MVC模式中的Controller,它 的首要職責是加載應用的佈局和初始化用戶界面,並接受並處理來自用戶的操作請求,進而作出響應。隨着界面及其邏輯的複雜度不斷提升,Activity類的 職責不斷增加,以致變得龐大臃腫。當我們將其中複雜的邏輯處理移至另外的一個類(Presneter)中時,Activity其實就是MVP模式中 View,它負責UI元素的初始化,建立UI元素與Presenter的關聯(Listener之類),同時自己也會處理一些簡單的邏輯(複雜的邏輯交由 Presenter處理).




(個人描述:)
總結爲一句話:
爲了讓安卓中的ui部分減少數據處理數量,將壓力減低,讓其他的部分幫他分解壓力,這樣說懂了吧?



2,那麼,mvp模式是如何進行設計與聯繫的呢?






     (1)View:負責繪製UI元素、與用戶進行交互(在Android中體現爲Activity);


     (2)View interface:需要View實現的接口,View通過View interface與Presenter進行交互,降低耦合,方便進行單元測試;


     (3)Model:負責存儲、檢索、操縱數據(有時也實現一個Model interface用來降低耦合);


     (4)Presenter:作爲View與Model交互的中間紐帶,處理與用戶交互的負責邏輯。




他們之間的關係可以這麼看:


首先分別介紹一下他們三個如何操作與使用的


   先說View,View你可以理解爲activity他是用來進行ui界面繪製的,一般情況下都會單獨建一個view接口,讓activity來實現他,實現的目的是什麼,是用來到後邊進行接口回調數據使用的。


這裏我從工程中粗略的切了幾張圖,殘缺不全,大家可以就當個意思,看的明白就行了;


如圖:

這是活動繼承了view,這裏的activity就可以被認爲ui界面,可以被叫做view,


 

/**
 * MVC   M  model 實體模型業務類   V 視圖    C 控制器
 *
 * MVP(Model View Presenter)
 *  view 通常activity或者fragment或者某個控件  負責view的繪製和用戶交互
 *  model 業務邏輯和實體模式  提供數據的存取功能
 *  Presenter 負責view和model層之間的交互  中間人 降低view層model層之間的耦合度
 *
 * MVP模式的好處:
 * 1.降低view層model層之間的耦合度 降低了view的複雜性 提高了可拓展性
 *
 * MVC和MVP之間的區別?
 *   MVC模式中允許model層和view層之間進行交互;MVP中 model和view之間交互由Presenter
 * 完成
 *  MVVM 與MVP類似 唯一的區別就是view與model雙向綁定 兩者之間一方放生變化則會影響到另一方
 *  MVVM與AdapterView與adapter的關係類型
 */
public class MainActivity extends AppCompatActivity implements
        IUserLoginView{
    private EditText et_name,et_pwd;
    private UserLoginPresenter presenter=new UserLoginPresenter(this);
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_name= (EditText) findViewById(R.id.et_userName);
        et_pwd= (EditText) findViewById(R.id.et_password);
        findViewById(R.id.btn_login).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.login();
            }
        });

        findViewById(R.id.btn_clear).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.clear();
            }
        });

    }

    @Override
    public String getUserName() {
        return et_name.getText().toString().trim();
    }

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

    @Override
    public void clearUserName() {
        et_name.setText("");
    }

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

    @Override
    public void loginSucess(User user) {
        Toast.makeText(this,user.getUserName()+"登錄成功!",Toast.LENGTH_LONG).show();
    }

    @Override
    public void showFailed() {
        Toast.makeText(this,"登錄失敗!",Toast.LENGTH_LONG).show();
    }
}

//這是view接口,提供了很多方法用來得到model中傳遞過來的數據,你在做界面操作的時候想一下你需要讓界面作什麼,就在這個view接口中聲明一個抽象方法,在這裏我讓view做的事情是

得到用戶姓名,

得到用戶密碼,

清除用戶姓名,

清除用戶密碼,成功失敗操作,

這裏先不管,接着往下看:


/**
 * 定義view層的接口  接口中定義什麼函數?
 * 觀察界面需要展示什麼信息  接口中定義什麼函數向activity中進行展示
 */
public interface IUserLoginView {
    //界面需要對view視圖做什麼操作都定義在該接口中
    //實現登錄功能時需要獲取用戶名和密碼
    public String getUserName();
    public String getPassword();

    //重置時需要清除用戶名和密碼
    public void clearUserName();
    public void clearPassword();

    //點擊登錄按鈕時成功或者失敗的情況
    public void loginSucess(User user);
    public void showFailed();
}



再說一下model,他是一個具體的進行邏輯編寫操作的類,如果需要也可以給model也創建一個接口,讓model來繼承;

這個接口決定了,子類要進行的工作,具體的邏輯 操作和運算就是去登陸界面,

**
 * model中的接口 業務邏輯類 抽取的接口 定義的業務邏輯類的方法
 */
public interface IUserBiz {
    public void login(String userName,String passWord,
                      OnLoginListener loginListener);
}




這裏在model的接口中寫了接口,實現此接口用來進行具體的邏輯操作,此處的model實現了model的抽象方法,裏面我模擬了一個具體的登陸操作,這裏用一個耗時睡眠代替,畢竟只是個demo我也犯不上去登陸別的服務器吧,哈哈,這個代碼還會少些。不是麼

/**
 * model層的具體的業務邏輯類
 */
public class UserBiz implements IUserBiz{
    //實現登錄的具體的業務邏輯
    @Override
    public void login(final String userName, final String passWord,
                      final OnLoginListener loginListener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                //工作線程模擬耗時操作 登錄聯網獲取具體結果
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                if("admin".equals(userName) && "admin".equals(passWord)){
                    User user=new User();
                    user.setUserName(userName);
                    user.setPassword(passWord);
                    loginListener.loginSuccess(user);
                }else{
                    loginListener.loginFaied();
                }
            }
        }).start();
    }
}

另外,單獨做一個接口回調:如果登陸成功的話就將user對象傳遞出去,

/**
 * 登錄操作的接口 登錄操作完成的結果
 * 登錄成功 登錄失敗的回調函數
 */
public interface OnLoginListener {
    public void loginSuccess(User user);
    public void loginFaied();
}

對了,這裏還得寫一個user的bean類,這個是個人demo需求,不是必須有的:

/**
 * 將用戶名和密碼封裝到用戶實體類中
 */
public class User {
    private String userName;
    private String password;

    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;
    }
}




再說一下Presenter:
他的作用非常簡單,他通過調用model中的方法,將model邏輯操作的數據通過activit的接口回調方式將數據結果傳回到activtiy中,你可以理解爲,工人model打工結束後,presenter將工人的勞動果實帶給activity,
他們之間的關係就是老闆(activity),工人(model),(使者或者說項目經理)的關係,


View不直接與Model交互,而是通過與Presenter交互來與Model間接交互
Presenter與View的交互是通過接口來進行的,更有利於添加單元測試
通常View與Presenter是一對一的,但複雜的View可能綁定多個Presenter來處理邏輯 



//presenter的實現類:本來如果工程量比較大的話Presenter也需要和上邊一樣創建抽象類的,畢竟這個鄙不是必須的,索性不添加了。免得你又會覺得凌亂;


/**
 * 中間人類 訪問model和view
 */
public class UserLoginPresenter {
    private IUserBiz userBiz;//model業務邏輯層
    private IUserLoginView userLoginView;//view視圖層
    //定義構造函數  IUserLoginView userLoginView=activity;
    public UserLoginPresenter(IUserLoginView userLoginView){
        this.userLoginView=userLoginView;
        this.userBiz=new UserBiz();//IUserBiz userBiz=new UserBiz();
    }

    Handler handler=new Handler();
//中間人操作登錄功能 中間人訪問業務邏輯層model層中的業務---結果展示到view層
    public void login(){
        //userBiz.login()中間人訪問 model業務邏輯層的函數
        //login()方法參數由view視圖層提供
        userBiz.login(userLoginView.getUserName(),
                userLoginView.getPassword(),
                new OnLoginListener() {
            @Override
            public void loginSuccess(final User user) {
                //提醒頁面登錄成功
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        userLoginView.loginSucess(user);
                    }
                });

            }

            @Override
            public void loginFaied() {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        userLoginView.showFailed();
                    }
                });
            }
        });
    }
//重置
    public void clear(){
      userLoginView.clearUserName();
      userLoginView.clearPassword();
    }


}

 如果有需要的大家可以參考一下運行以下結果,對了,這裏把佈局也直接補上吧:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    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"
    tools:context="com.yztc.mvpdemo.MainActivity"
    android:orientation="vertical">

    <EditText
        android:id="@+id/et_userName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="請輸入用戶名"
        android:textSize="25sp"/>
    <EditText
        android:id="@+id/et_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="請輸入密碼"
        android:inputType="textPassword"
        android:textSize="25sp"/>
    <Button
        android:id="@+id/btn_login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="登錄"
        android:textSize="20sp"/>
    <Button
        android:id="@+id/btn_clear"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="重置"
        android:textSize="20sp"/>
</LinearLayout>




寫到這裏或許你對mvp有了一些認識,但是mvp是從mvc繁衍過來的,爲什麼會出現mvp那是因爲mvc模式不能夠很好的將view和model進行分離,

你會問,什麼是mvc?

mvc就是model view controller,意思和mvp差不多,但是兩者的區別就是,view和model是可以直接進行交互的,而mvp中兩者的交互使用prosster當了中間人,這樣更好的將view和mldel進行了隔離。

 


發佈了39 篇原創文章 · 獲贊 14 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章