MVC與MVP架構模式
MVC架構模式
MVC全稱是Model-View-Controller也就是模型-檢視-控制器,MVC是一個框架模式而非設計模式,那麼框架模式和設計模式又有什麼區別呢?框架模式中會用到設計模式,你可以簡單的理解框架面向於一系列相同行為程式碼的重用,設計則面向的是一系列相同結構程式碼的重用。
MVC在Android中的應用
Android中對MVC的應用很經典,對Android本身來說,其介面部分的開發就涉及了模型-檢視-控制器3者的互動,在Android中檢視view層一般採用xml檔案進行介面的描述,比如以下一段比較常見的xml佈局檔案程式碼
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout 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="com.example.huangli.bridgepattern.MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>
對於模型Model層大多對應於本地的資料檔案或網路獲取的資料體,很多情況下我們的對資料處理的業務邏輯也會在這一層,Controller層對應的則是Activity.
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
一般情況下會在Activity中獲取資料以及介面元素,並將兩者進行繫結. Activity的作用主要是解耦,將檢視View和模型Model進行分離,兩者在Activity中進行繫結。
MVP架構模式
MVP全稱Model View Presenter,之前提到的MVC模式,常常會在Activity中夾雜著業務邏輯,比如說非同步請求後再次非同步請求,使得Activity變得臃腫, MVP能夠有效的降低這種複雜性,MVP可以接觸View和Model的耦合,通過Presenter。
MVP可以分離顯示層和邏輯層,它們之間使用介面進行通訊,降低耦合.

Presenter-互動中間人
Presenter主要作為溝通View和Model的橋樑,它從Model層檢索資料後,返回給View層,使得View和Model之間沒有耦合,它將業務邏輯從View角色上抽離出來.
View-使用者介面
View通常是指Activity,Fragment或者某個View控制元件,它含有一個Presenter成員變數。通常View需要實現一個邏輯介面,將View上的操作通過會交給Presenter進行實現,最後,Presenter呼叫View邏輯介面將結果返回給View元素
Model-資料的存取
對於一個結構化的App來說,Model角色主要是提供資料的存取功能。Presenter需要通過Model層儲存,獲取資料,Model就像一個數據倉庫。更直白的說,Model是封裝了資料庫DAO或者網路獲取資料的角色,或者兩種資料獲取方式的集合.
這裡我們回頭看看MVC

它的問題:
1,可以看出MVC的耦合性是比MVP高的,View是可以和Model互相訪問的(例如在一些自定義view中,不依附於Activity去獲取資料進行存取)
2,在MVC中Activity是作為Controller的,但是在MVP中Activity就是View層了,在Activity充當Controller過程的時候或多或少會涉及到部分業務邏輯,在MVP中就完全不會出現這種Activity夾雜業務邏輯的情況.
如果使用MVP架構就可以解決掉這種高耦合性的問題。

我們使用MVP的設計模式去做一個登入的操作,首先我們必須要明確一點的是Presenter是通過介面對View進行操作的,所以我們要設計一套登入介面讓Activity繼承
public interface IUserLoginView { String getUserName(); String getPassword(); void clearUserName(); void clearPassword(); void showLoading(); void hideLoading(); void toMainActivity(User user); void showFailedError(); }
接下來是Presenter
public class UserLoginPresenter { private IUserLoginView iUserLoginView; private IUserBiz userBiz; private Handler mHandler = new Handler(); public UserLoginPresenter(IUserLoginView iUserLoginView) { this.iUserLoginView = iUserLoginView; userBiz = new UserBiz(); } public void login(){ iUserLoginView.showLoading(); userBiz.login(iUserLoginView.getUserName(), iUserLoginView.getPassword(), new OnLoginListener() { @Override public void loginSuccess(final User user) { mHandler.post(new Runnable() { @Override public void run() { iUserLoginView.toMainActivity(user); iUserLoginView.hideLoading(); } }); } @Override public void loginFail() { iUserLoginView.showFailedError(); iUserLoginView.hideLoading(); } }); } }
可以看出來UserLoginPresenter中有一個IUserLoginView的引用,我們操作View就靠它了,接下來是一些業務邏輯相關的程式碼,也就是Model層
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; } }
public interface IUserBiz { void login(final String username,final String password, final OnLoginListener loginListener); }
public interface OnLoginListener { void loginSuccess(User user); void loginFail(); }
public class UserBiz implements IUserBiz { @Override public void login(final String username,final String password, final OnLoginListener loginListener) { new Thread(){ @Override public void run() { super.run(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } if ("zhy".equals(username) && "123".equals(password)){ User user = new User(); user.setPassword(password); user.setUsername(username); loginListener.loginSuccess(user); }else{ loginListener.loginFail(); } } }.start(); } }
最終讓Activity繼承IUserLoginView,然後初始化UserLoginPresenter.
public class MvpDemoActivity extends Activity implements IUserLoginView { private UserLoginPresenter userLoginPresenter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); userLoginPresenter = new UserLoginPresenter(this); } @Override public String getUserName() { return null; } @Override public String getPassword() { return null; } @Override public void clearUserName() { } @Override public void clearPassword() { } @Override public void showLoading() { } @Override public void hideLoading() { } @Override public void toMainActivity(User user) { } @Override public void showFailedError() { } }
以上就是一個 mvp架構設計的一個登入流程.
MVP與Activity,Fragment的生命週期
mvp有很多優點,易於維護,易於測試,鬆耦合,複用性高,健壯穩定,易於擴充套件等. Presenter通常會執行一些耗時操作,這樣它把持者Activity就會導致記憶體洩露。我們可以通過弱引用來解決。
public abstract class BasePresenter<T>{ protected Reference<T> mViewRef; public void attachView(T view){ mViewRef = new WeakReference<T>(view); } protected T getView(){ return mViewRef.get(); } public boolean isViewAttached(){ return mViewRef != null && mViewRef.get() != null; } public void detachView(){ if (mViewRef != null){ mViewRef.clear(); mViewRef = null; } } }
BasePresenter中把持一個WeakReference,WeakReference用來存放外部View的引用
public abstract class MVPBaseActivity<V,T extends BasePresenter<V>> extends Activity{ protected T mPresenter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mPresenter = createPresenter(); mPresenter.attachView((V)this); } @Override protected void onDestroy() { super.onDestroy(); mPresenter.detachView(); } protected abstract T createPresenter(); }
MVPBaseActivity用來建立與BasePresenter的關係,最終我們的Activity和Presenter分別繼承於它們
public class ActualPresenter extends BasePresenter<IUserLoginView>{ public ActualPresenter() { } }
public class ActualMVPActivity extends MVPBaseActivity<IUserLoginView,ActualPresenter>{ @Override protected ActualPresenter createPresenter() { return null; } }
這裡因為BasePresenter維護的是一個Activity的弱引用,所以就不會存在Activity在onDestory後Presenter執行耗時操作Activity不被釋放導致記憶體洩露.
總結
MVP是一個非常值得推薦的設計模式,它帶來了可擴充套件性,可測試性,穩定性,可維護性.
【附錄】

資料圖