MVP架構由淺入深篇一(基礎版)
MVP架構由淺入深篇一
前言:不得不說,才開始學習MVP架構各種介面的呼叫和解耦程式碼真的讓人眼花繚亂,對於很多問題都是一知半解:
- 關於如何在Activity中高效的複用Presenter和View;
- Mode層定義到什麼程度才算是比較理想的解耦;
- Model層與Presenter層如何比較優雅的相互通訊。
所以決定靜下心來理解一下該架構的藝術。部落格主要參考https://www.jianshu.com/p/5c3bc32afa36?utm_campaign=haruki,其中加入自己的理解和程式碼實現來學習和驗證MVP架構的使用技巧。
目錄
一、MVP架構概述
1.為什麼要使用MVP架構?
MVP(Model、View、Presenter)模式將Activity中的業務邏輯分離出來,避免了Activity邏輯的高耦合,可以把Model理解成房東,View就是找房的自己,Presenter就是中介,讓Activity只做UI的功能,把其他功能抽出去讓其他層來完成,缺點就是程式碼量增加了,但是帶來的優點遠超缺點,尤其是專案比較大的時候更是事半功倍。
2.MVP理論知識
在MVP架構中跟MVC類似分為三層。
- Activity和Fragment視為View層 --> 理解為四處找房的自己
- Presenter為業務處理層,既能呼叫UI邏輯,又能請求資料 --> 相當於中介公司
- Model層中包含著具體的資料請求,資料來源 --> 相當於房東
三層之間呼叫順序為view-->presenter-->model,不能反向呼叫和跨級呼叫
由上圖可知,Model層通過Callback反饋資料給Presenter層,Presenter層通過View反饋操作給Activity層。其中View和Callback都是以介面的形式存在。
- Callback中定義了請求資料時反饋的各種狀態:成功、失敗、錯誤等
- View中定義了Activity的具體操作,主要是將請求得到的資料在介面上更新
二、基礎版MVP程式碼實現
因為是模擬網路資料請求,所以有三個請求資料的按鈕分別對應成功、失敗、異常三種不同的反饋狀態。
1.檔案結構
2.Callback介面
因為Callback介面是presenter和model打交道的介面,所以介面中定義了請求資料的方法
package com.example.mvpapplication;
/**
* callback負責presenter和model互動
* 相當於:中介和房東互動介面
*/
public interface MvpCallback {
/**
* 請求資料成功
* @param data
*/
void onSuccess(String data);
/**
* 使用網路API介面請求,請求資料失敗
* @param msg
*/
void onFailure(String msg);
/**
* 請求資料時發生錯誤
*/
void onError();
/**
* 請求資料完成
*/
void onComplete();
}
3.Model 類
Model 類中定了具體的網路請求操作。利用postDelayed
方法模擬耗時操作,通過判斷請求引數反饋不同的請求狀態:(房東)
package com.example.mvpapplication;
import android.os.Handler;
public class MvpModel {
/**
* 獲取網路資料
* @param param 請求引數
* @param callback 資料回撥介面 -- callback相當於房東如果有房子就要回復給中介
*/
public static void getNetData(final String param,final MvpCallback callback){
//利用postDelayed方法模擬網路請求資料的操作
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
switch (param){
case "normal":
callback.onSuccess("根據引數"+param+"的請求網路資料成功");
break;
case "failure":
callback.onFailure("請求資料失敗");
break;
case "error":
callback.onError();
break;
}
callback.onComplete();
}
},2000);
}
}
4.View 介面
View介面是Activity與Presenter層的中間層,它的作用是根據具體業務的需要,為Presenter提供呼叫Activity中具體UI邏輯操作的方法。相當於我和中介之間的交易
package com.example.mvpapplication;
/**
* 這裡相當於找房子的自己--對UI進行操作的介面
*/
public interface MvpView {
/**
* 顯示正在載入資料進度
*/
void showLoading();
/**
* 隱藏進度
*/
void hideLoading();
/**
* 展示資料
* @param data
*/
void showData(String data);
/**
* 顯示資料錯誤原因回撥介面
* @param msg
*/
void showFailureMessage(String msg);
/**
* 當資料錯誤時回撥介面
*/
void showErrorMessage();
}
5.Presenter類
Presenter類是具體的邏輯業務處理類,負責請求資料,並對資料請求的反饋進行處理。Presenter相當於中介的作用,所以裡面要有MvpView和Callback的宣告。
package com.example.mvpapplication;
/**
* 這裡相當於中介的作用
*/
public class MvpPresenter {
//因為中介要和僱主打交道,所以要宣告MvpView
private MvpView mView;
public MvpPresenter(MvpView view){
this.mView = view;
}
/**
* 相當於幫我找房子--請求資料
* @param param
*/
public void getData(String param){
//顯示正在載入進度條
mView.showLoading();
//呼叫Model請求資料
MvpModel.getNetData(param, new MvpCallback() /*開始和Model打交道的介面*/{
@Override
public void onSuccess(String data) {
//呼叫view介面顯示資料
mView.showData(data);
}
@Override
public void onFailure(String msg) {
mView.showFailureMessage(msg);
}
@Override
public void onError() {
mView.showErrorMessage();
}
@Override
public void onComplete() {
mView.hideLoading();
}
});
}
}
6.佈局檔案
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="點選按鈕獲取網路資料"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="獲取資料【成功】"
android:onClick="getData"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="獲取資料【失敗】"
android:onClick="getDataForFailure"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="獲取資料【異常】"
android:onClick="getDataForError"
/>
</LinearLayout>
7.MainActivity
在MainActivity中,主要是對MvpView的實現,進行UI操作
package com.example.mvpapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements MvpView{
//進度條
ProgressDialog progressDialog;
TextView text;
//找到中介
MvpPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = findViewById(R.id.text);
//初始化進度條
progressDialog = new ProgressDialog(this);
progressDialog.setCancelable(false);
progressDialog.setMessage("正在載入中...");
//初始化presenter
presenter = new MvpPresenter(this);
}
/**
* button事件
*/
public void getData(View view){
presenter.getData("normal");
}
public void getDataForFailure(View view){
presenter.getData("failure");
}
public void getDataForError(View view){
presenter.getData("error");
}
@Override
public void showLoading() {
if (!progressDialog.isShowing()){
progressDialog.show();
}
}
@Override
public void hideLoading() {
if (progressDialog.isShowing()){
progressDialog.dismiss();
}
}
@Override
public void showData(String data) {
text.setText(data);
}
@Override
public void showFailureMessage(String msg) {
Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();
text.setText(msg);
}
@Override
public void showErrorMessage() {
Toast.makeText(this,"請求異常",Toast.LENGTH_SHORT).show();
text.setText("請求異常");
}
}
8.執行結果:(以成功請求資料為例)
至此,基礎版MVP已經完成了,下面我們來分析一下基礎版存在的問題和如何優化?
三、基礎版MVP問題分析
通過上面的程式碼實現,看似已經完成了MVP的框架了,但是遠遠不夠,其中一個問題就是複用問題。
由於上述例子我們只有一個業務邏輯,即只有一個Activity,那如果有兩個或者更多Activity呢?我們需要建立N多個MVP框架嗎?當然在不需要MVP的Activity中當然不用建立,可是當需要MVP的Activity呢?當然這也要分情況,如果Activity業務邏輯相似當然可以複用,但是當業務邏輯不一樣時,就必須建立另一個MVP了。可是又如何複用業務邏輯相似的MVP呢?請看下述分析:
場景1:業務邏輯完全相同
這種場景很簡單,由於業務邏輯完全相同,就直接複用就好了。
場景2、3:包含部分相同業務邏輯
場景2和場景3的邏輯類似,都屬於一個業務邏輯中包含另外一個可以單獨存在的業務邏輯,這種情況採用繼承的方法即可。
場景4
場景4中Activity C想要同時呼叫獨立服務於Activity A 和 Activity B的業務邏輯,只需要將兩個業務邏輯對應的Presenter分別例項化並呼叫業務方法即可。
場景5
場景5屬於場景3與場景4的結合體,同樣需要先把A和B的業務邏輯拆分開,然後同時呼叫。
基礎版MVP總結
從上述的分析可知,基礎版MVP存在複用問題。由於MVP框架還算是比較繁重的,所以複用很有必要,可以減少很多沒必要的重複程式碼。我們能想到的方法就是類比Binder連線池,在Presenter層寫完整的業務邏輯,然後通過不同的業務標誌進行不同的業務處理,這種方式很簡單,但是這樣的話,可能會有一定的問題,比如Presenter層業務過於繁重,維護較難等。畢竟架構師提出的複用方案是實踐得出的真理,存在即是合理的。在下一篇中,我們將介紹進階版MVP框架的實現。
相關文章
- iOS架構由淺入深 | MVVMiOS架構MVVM
- 【由淺入深_打牢基礎】HOST頭攻擊
- promise由淺入深Promise
- MySql架構原理(MySql從淺入深 一)MySql架構
- 死磕安卓前序:MVP架構探究之旅—基礎篇安卓MVP架構
- 由淺入深 docker 系列: (2) docker 構建Docker
- JavaScript Promise由淺入深JavaScriptPromise
- MySQL索引由淺入深MySql索引
- Git 由淺入深之細說變基 (rebase)Git
- 物件導向-由淺入深物件
- [轉帖]由淺入深瞭解GC入門篇(一):什麼是垃圾回收?GC
- iOS MVC、MVVM、MVP架構模式淺淺析iOSMVCMVVMMVP架構模式
- 純手寫Promise,由淺入深Promise
- 由淺入深理解 IOC 和 DI
- Vue.js 2.0 由淺入深Vue.js
- 零基礎深度學習入門:由淺入深理解反向傳播演算法深度學習反向傳播演算法
- C#非同步程式設計由淺入深(一)C#非同步程式設計
- 第十八節:Skywalking由淺入深
- 由淺入深 docker 系列: (3) docker-composeDocker
- 由淺入深理解Dubbo的SPI機制
- 由淺入深完全理解Java動態代理Java
- 由淺入深 docker 系列: (6) 映象分層Docker
- 【Fastjson】Fastjson反序列化由淺入深ASTJSON
- iOS架構淺談從 MVC、MVP 到 MVVMiOS架構MVCMVPMVVM
- Python基礎入門知識點——深淺拷貝Python
- 由淺入深 docker 系列: (5) 資源隔離Docker
- 架構設計之一——基礎架構架構
- Android MVP 架構AndroidMVP架構
- 前端如何理解正則-由淺入深的學習前端
- Android架構系列-基於MVP建立適合自己的架構Android架構MVP
- 基礎架構遷雲(一)架構
- 由淺入深瞭解羚瓏平臺統一接入服務 —— Monet
- 由淺入深!一文5張圖教你做效能測試~
- Abp vNext 基礎篇丨分層架構架構
- 由淺到淺入門批量渲染(一)
- JS基礎入門篇( 一 )JS
- JS基礎入門篇(一)JS
- Android-MVP架構AndroidMVP架構