(官方描述:)
關於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進行了隔離。