目錄
- MVP簡介
- MVP結構
- MVP與MVC區別
- 實戰演習
正文
1、MVP簡介
相信大家對MVC都是比較熟悉了:M-Model-模型、V-View-視圖、C-Controller-控制器,MVP作爲MVC的演化版本,那麼類似的MVP所對應的意義:M-Model-模型、V-View-視圖、P-Presenter-表示器。從MVC和MVP兩者結合來看,Controlller/Presenter在MVC/MVP中都起着邏輯控制處理的角色,起着控制各業務流程的作用。而MVP與MVC最不同的一點是M與V是不直接關聯的也是就Model與View不存在直接關係,這兩者之間間隔着的是Presenter層,其負責調控View與Model之間的間接交互,MVP的結構圖如下所示,對於這個圖理解即可而不必限於其中的條條框框,畢竟在不同的場景下多少會有些出入的。在Android中很重要的一點就是對UI的操作基本上需要異步進行也就是在MainThread中才能操作UI,所以對View與Model的切斷分離是合理的。此外Presenter與View、Model的交互使用接口定義交互操作可以進一步達到松耦合也可以通過接口更加方便地進行單元測試。
(引用該文章:http://zhengxiaopeng.com/2015/02/06/Android中的MVP/)
2、MVP結構
View View通常來說就是有Activity、Fragment實現的,View會包含一個或多個Presenter的引用來滿足視圖的業務邏輯。View和Presenter的交互是雙向的,即View層可以調用Presenter的邏輯方法,Presenter也可以控制View的顯示。 Presenter Presenter作爲Model和View的橋樑,負責從Model拿到數據進行處理並返回給View。但Presenter和其他兩層的溝通是通過接口協議進行的,所以每個Presenter中通常會包涵一個或多個接口協議。 Model 和MVC一樣,作爲數據倉庫只負責對APP數據進行處理。 Android開發MVP模式實踐中的示例將APP分爲以下四層。
Entities:APP中的業務類。 Use Cases:負責從將Entities中的數據進行處理和包裝。 Presenters:從Use Cases獲取處理好的數據,然後根據需求邏輯爲UI提供合適的數據。 UI:從Presenters獲取處理好的最終數據,和用戶進行直接交互。 這四層設計的原則是代碼調用只能從外圓向內圓擴展,內圓不能干預也不需關心外圓的功能邏輯,這符合MVP的思想,Use Cases和Presenters將Entities和UI間隔分離,從而使Entities和UI只需關心自身邏輯,數據處理完全交給其他兩層。 這裏,有些同學可能會有疑問,說好的Presenters爲什麼會有Use Cases出來攪局?其實這也是我選擇這個工程當做示例的目的,看了好多MVP文章,都在講Presenter如何通過接口協議和其他兩層進行交互,但大都忽略了Presenter層自身的構架,因爲僅僅套用MVP模式,雖然在一定程度上降低View的耦合度,但因爲Presenter既要處理數據,又要結合需求控制UI交互,所以很可能出現Presenter邏輯的冗餘。後文的示例工程在Presenter和Model之間包裝了Use Cases,將數據邏輯處理交給UseCases從而讓Presenter更專心於UI交互。
(引用該文章:http://blog.csdn.net/guxiao1201/article/details/40147209)
3、MVP與MVC區別
在把原本MVC模式的代碼修改爲MVP模式後,總結這兩個模式在實際使用過程中的不同點基本上總結爲兩點: 各個層之間通過接口協議進行溝通; View和Model不再進行直接交互;
(詳細說明請參考MVC or MVP Pattern - Whats the difference?)
4、實戰演習
模擬登錄功能,實現MVP架構模式。下面是實戰的具體步驟
NO1、新建VIew公共部分接口:
/**
* Created by Bluesky on 2015/8/27.
* MVP中V層的公共接口
*/
public interface IView {
public void showProgressPar();
public void hideProgressPar();
public void showError(Object o);
}
View繼承公共IView接口
/**
* Created by Bluesky on 2015/8/27.
* 登錄View接口
*/
public interface ILogin extends IView {
public void showSuccess(Object o);
}
NO2、VIew的實現。也就是Activity實現ILogin接口:
/**
*登錄頁面Activity
*/
public class MainActivity extends Activity implements ILogin {
private LoginPresenter mPresenter;
private User mUser;
private ProgressDialog mDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPresenter = new LoginPresenter(this);
mUser = new User();
initVIew();
}
private void initVIew() {
final EditText pwd = (EditText) findViewById(R.id.pwd);
final EditText name = (EditText) findViewById(R.id.name);
Button loginBtn= (Button) findViewById(R.id.login_btn);
loginBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mUser.setName(name.getText().toString());
mUser.setPassword(pwd.getText().toString());
mPresenter.login(mUser);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void showSuccess(Object o) {
User user= (User) o;
Toast.makeText(this,"登錄成功信息:"+user.getName()+" /"+user.getPassword(),Toast.LENGTH_LONG).show();
}
@Override
public void showProgressPar() {
mDialog = new ProgressDialog(MainActivity.this);
mDialog.setMessage("正在加載...");
mDialog.show();
}
@Override
public void hideProgressPar() {
mDialog.hide();
}
@Override
public void showError(Object o) {
Toast.makeText(this,"異常:"+((Exception)o).getMessage(),Toast.LENGTH_LONG).show();
}
}
activity的xml佈局:
<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:orientation="vertical"
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=".MainActivity"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world"/>
<EditText
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入用戶名"
/>
<EditText
android:id="@+id/pwd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入密碼"
/>
<Button
android:id="@+id/login_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="登錄"/>
</LinearLayout>
No3、新建LoginPresenter。我們面向接口編程,所以,新建一個Presenter接口,在該Demo是沒有什麼方法,這是爲了可擴展性考慮。 presenter接口
/**
* Created by Bluesky on 2015/8/27.
* MVP中P層
*/
public interface Presenter {
}
登錄presenter實現presenter接口,在這裏進行View和Model層橋樑連接,進行業務調度,起到指揮作用
/**
* Created by Bluesky on 2015/8/27.
*/
public class LoginPresenter implements Presenter {
private ILogin mLoginView;
private ILoginBiz mLoginBiz;
private Handler mHandler = new Handler();
public LoginPresenter(ILogin mLoginView) {
this.mLoginView = mLoginView;
this.mLoginBiz = new LoginBizImpl();
}
/**
* 登錄
*
* @param o
*/
public void login(Object o) {
mLoginView.showProgressPar();
mLoginBiz.login(o, new Listener() {
@Override
public void complete() {
mHandler.post(new Runnable() {
@Override
public void run() {
mLoginView.hideProgressPar();
}
});
}
@Override
public void onSuccess(final Object o) {
mHandler.post(new Runnable() {
@Override
public void run() {
mLoginView.showSuccess(o);
}
});
}
@Override
public void onFailed(final Exception e) {
mHandler.post(new Runnable() {
@Override
public void run() {
mLoginView.showError(e);
}
});
}
});
}
}
No4、Model層進行業務邏輯處理。新建model層接口,然後實現業務邏輯處理,做異步處理及子線程和主線程通訊。 model接口:
/**
* Created by Bluesky on 2015/8/27.
*/
public interface ILoginBiz {
public void login(Object o,Listener listener);
}
model實現:
/**
* Created by Bluesky on 2015/8/27.
*/
public class LoginBizImpl implements ILoginBiz {
@Override
public void login(Object o, final Listener listener) {
final User user = (User) o;
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
listener.complete();
if (user.getName().equals(user.getPassword())) {//成功
listener.onSuccess(user);
} else {//失敗
listener.onFailed(new Exception("運行異常..."));
}
}
}).start();
}
}
實體類:
/**
* Created by Bluesky on 2015/8/27.
*/
public class User implements Serializable {
private String name;
private String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
回調接口:
/**
* Created by Bluesky on 2015/8/27.
*/
public interface Listener {
public void complete();
public void onSuccess(Object o);
public void onFailed(Exception e);
}
源代碼
https://github.com/hrx3627/MVPAndroidDemo
參考信息
http://www.imooc.com/wenda/detail/216700http://www.cnblogs.com/daizhj/archive/2009/04/30/1447035.HTMLhttp://blog.csdn.net/lmj623565791/article/details/46596109http://zhengxiaopeng.com/2015/02/06/Android中的MVP/http://blog.csdn.net/guxiao1201/article/details/40147209
個人信息
- 微信:huangrx1988
- 博客:http://blog.csdn.net/hrx3627
- github:https://github.com/hrx3627
- Android交流QQ羣 :367818514
- QQ:1084986314