Android MVP經驗談
歡迎轉載,轉載時請註明出處和作者
作者:kerwin
原文地址:
http://www.jianshu.com/p/284990eebf0c
****MVP->Model-View-Presenter****,意在解決業務邏輯與視覺層的解耦問題。關於MVC與MVP的區別相關資料很多,這裡不再累述,相關傳送門:
MVP模式(百度百科)
從上圖看出,Presenter是作為Model與View層互動的聯結器存在。將上圖轉化為程式碼實現的官方例項:Google官方architecture專案。
MVP模式類圖
類圖解析
核心的3個介面:BaseUI、BasePresenter、XContract。
****BasePresenter****,業務實現層的基礎介面,所有Presenter的超父類,
方法:start(Bundle bundle),Presenter層的資料初始化,Bundle為常規頁面資料傳遞的基本容器。
****BaseUI****,檢視層的基礎介面,所有UI實現類的超父類
方法:setPresenter(T presenter),用於關聯UI與Presenter,主要用在Fragment與Presenter的繫結。
****XContract****,主要是為了將具體的UI和Presenter集合到一個檔案中,方便集中查閱管理。
實踐
需求:X頁面包含3個需求。1、計算總成績a+b,2、獲取X的姓名和性別,3、展示總成績和X的資訊。
1)首先按照需求寫出對應的Model類
public class XModle {
/**
* @param a a課程分數
* @param b b課程分數
* @return 總分數
*/
public int sum(int a, int b) {
return a + b;
}
/**
* 假裝這裡是從伺服器獲取的資料
* @param callback
*/
public void getX(Callback callback) {
callback.onResult("kerwin", "boy");
}
public interface Callback {
void onResult(String name, String gender);
}
}
2)建立XContract類
public interface XContract {
interface UI extends BaseUI<Presenter> {
}
interface Presenter extends BasePresenter {
}
}
3)根據業務需求新增UI和Presenter介面的方法
public interface XContract {
/**
* A課程得分的傳遞的引數名
*/
String PARAM_INT_A = "a";
/**
* B課程得分的傳遞的引數名
*/
String PARAM_INT_B = "b";
interface UI extends BaseUI<Presenter> {
/**
* 通知UI,Sum已經計算出來,可以重新整理對應的UI了
*/
void refreshSumResult();
/**
* 通知UI,X的資訊已經獲取到,可以重新整理X了。
*/
void refreshX();
/**
* 顯示loading彈窗
* @param msg
*/
void showLoading(String msg);
/**
* 關閉loading彈窗
*/
void dismissLoading();
}
interface Presenter extends BasePresenter {
/**
* 獲取X的姓名
* @return
*/
String getXName();
/**
* 獲取X的性別
* @return
*/
String getXGender();
/**
* 獲取總成績
* @return
*/
String getSumScore();
}
}
4)實現XPresenter類
public class XPresenter implements XContract.Presenter {
private XContract.UI ui;
private XModle modle;
private int a, b;
private int sum = 0;
private String xName, xGender;
public XPresenter(XContract.UI ui) {
this.ui = ui;
this.modle = new XModle();
}
@Override
public void start(Bundle bundle) {
a = bundle.getInt(XContract.PARAM_INT_A, 0);
b = bundle.getInt(XContract.PARAM_INT_B, 0);
start();
}
private void start() {
sum = modle.sum(a, b);
ui.refreshSumResult();
ui.showLoading("正在獲取X的資訊");
modle.getX(new XModle.Callback() {
@Override
public void onResult(String name, String gender) {
ui.dismissLoading();
xName = name;
xGender = gender;
ui.refreshX();
}
});
}
@Override
public String getXName() {
return "姓名:"+xName;
}
@Override
public String getXGender() {
return "性別:"+xGender;
}
@Override
public String getSumScore() {
return "總成績"+sum;
}
}
到這裡,可以看到,我們Activity還沒有開始寫,但是我們的業務流程已經完成了,這就是MVP的魅力。至於頁面長什麼樣子並不需要業務邏輯層去關注。現在我們理一下整個需求完成的程式流圖。
****程式流圖****
看過程式流圖後結合之前的程式碼,可能會問:為什麼UI裡面沒有setXName方法,為什麼Presenter裡面有getXName方法。為什麼Presenter從XModel裡面獲取到Sum返回值後不是直接呼叫ui.setSum(sum),而是ui.refreshSumResult()?
個人實踐中發現,UI層是隨時可能會變化的,但是Presenter基本不變,因為介面基本不變。所以,我推薦的MVP實踐方式是,主動的在UI中從Presenter獲取資料,而不是在Presenter中主動的修改UI資訊,Presenter完成從Model獲取資料的職責後僅需通知UI已經完成資料獲取,UI想如何顯示或顯示什麼自己決定。
****下面繼續完善UI部分的實現程式碼****
5)新增layout檔案activity_x.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp">
<TextView
android:id="@+id/tv_sum"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_x_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp" />
<TextView
android:id="@+id/tv_x_gender"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp" />
</LinearLayout>
6)新增XActivity類
public class XActivity extends Activity implements XContract.UI {
private TextView tv_x_name;
private TextView tv_x_gender;
private TextView tv_sum;
private XContract.Presenter presenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_x);
initView();
initPresenter();
}
private void initView() {
tv_sum = (TextView) findViewById(R.id.tv_sum);
tv_x_name = (TextView) findViewById(R.id.tv_x_name);
tv_x_gender = (TextView) findViewById(R.id.tv_x_gender);
}
private void initPresenter() {
presenter = new XPresenter(this);
presenter.start(getIntent().getExtras());
}
@Override
public void setPresenter(XContract.Presenter presenter) {
// 如果UI實現是一個Fragment,這裡的程式碼是需要的,是Activity的這裡留空即可
this.presenter = presenter;
}
@Override
public void refreshSumResult() {
tv_sum.setText(presenter.getSumScore() + "");
}
@Override
public void refreshX() {
tv_x_name.setText(presenter.getXName());
tv_x_gender.setText(presenter.getXGender());
}
@Override
public void showLoading(String msg) {
//顯示Dialog彈窗
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
@Override
public void dismissLoading() {
//關閉Dialog彈窗
}
}
至此,所有的需求全部完成了。
****說在最後****
MVP每一層都有自己的職責,請儘量做到各司其職。
幾點實踐建議:
1、View層不包含任何Model層的程式碼以及引用
2、Presenter作為聯結器,儘量不要直接呼叫UI層的具體UI更新的方法,僅需通知UI層自己去重新整理某一個細分模組(就像上面的refreshX)
相關文章
- 談談Android中的MVPAndroidMVP
- Android SDK 開發經驗淺談Android
- 談談 Android MVP 架構 | 掘金技術徵文AndroidMVP架構
- 經驗談
- 淺談Android中的mvc,mvp,mvvmAndroidMVCMVPMVVM
- 經驗談集
- DBA 經驗談
- 爆破經驗談
- 淺談MVPMVP
- 使用nfs經驗談NFS
- 大學打架經驗談
- Lotus 經驗談(轉)
- MVC、MVP、MVVM,談談我對Android應用架構的理解MVCMVPMVVMAndroid應用架構
- FIFO設計驗證經驗談
- Hugo 建站經驗之談Go
- Oracle 學習經驗談Oracle
- Doxygen簡單經驗談。。。
- ERP經驗談(轉)
- SAP學習經驗談
- Linux安全經驗談Linux
- JGraph開發經驗談
- 雜談: MVC/MVP/MVVMMVCMVPMVVM
- 談談Ilog的開發經驗
- puppeteer踩坑經驗之談
- 淺談SAP學習經驗
- 微軟測試工作經驗談微軟
- TurboLinux使用經驗談(轉)Linux
- CVS使用經驗談 (轉)
- 談談對MVC、MVP和MVVM的理解?MVCMVPMVVM
- Android Mvp實踐AndroidMVP
- Android MVP 架構AndroidMVP架構
- Android MVP 實踐AndroidMVP
- 10年出海老兵的經驗談
- kotlin開發經驗談3Kotlin
- kotlin開發經驗談4Kotlin
- kotlin開發經驗談5Kotlin
- Facebook應用Mercurial經驗談
- kotlin開發經驗談2Kotlin