提起MVP架構模式,大家可能首先想到的是它的“前輩”MVC模式。MVC由Model、View、Controller組成,請求從Controller進入后進行業務判斷,然后交給Model或View進行處理。這本身沒什么,但是應用在Android程序中時,大家就會發現,Activity既擔任了Controller的角色進行業務篩選,又擔任了View的角色進行界面展示,甚至有些時候還會擔任Model的角色加載數據。這就使的Activity中的代碼變得很多很長,而且功能雜亂,不便區分。怎么辦呢?於是,MVP模式就誕生了。
MVP由Model、View和Presenter組成,和MVC相似,MVP中的Model層也是用來加載數據的,View層也是用來展示界面的,MVP中獨有的Presenter是用來連接Model和View兩層,起到解耦的作用。下圖展示了MVC模式和MVP模式的工作流程上的比較:

從圖中可以看到,MVP模式中的View層和Model層之間沒有連線,即這兩層之間沒有直接的關聯,它們之間的交互是通過Presenter來完成的,這樣就實現的View和Model兩層的解耦。具體的MVP內部的工作流程如下圖所示:

可以看到,用戶首先在View層中進行操作,將用戶動作傳到Presenter中,Presenter將動作傳遞到Model中進行處理,然后將處理結果傳回到Presenter,再由Presenter相應到View中。
MVP模式的整體架構是通過接口來搭建的,我們需要一個整體的架構管理類Contract來管理Model、View、Presenter這三個接口,Model類、View類和Presenter類都分別實現這三個接口。Presenter中持有Model和View的引用,Presenter中的所有方法都會調用Model中對應的方法進行處理;Model中寫實際代碼;View是被Activity實現的,其中持有一個Presenter的引用,所有方法都會調用Presenter的對應方法。
下面貼出一個簡單的DEMO中的代碼。
DEMO的界面非常簡單,只有一個按鈕,當我們點擊按鈕的時候彈出一個Toast,就是這么一個簡單的DEMO,我們嘗試用MVP模式來搭建,編寫。
首先我們需要一個接口的統一管理類MainContract,這個類中包含了M、V、P三個接口,接口中定義抽象方法。這里我們只打算有一個方法,即按鈕點擊事件onButtonClicked()方法。代碼如下:
public class MainContract { interface View { void onButtonClicked(String text); } interface Model { void onButtonClicked(Context context, String text); } interface Presenter { void onButtonClicked(Context context, String text); } }
有了接口之后,我們讓M、V、P三層的具體類來實現這三個接口,這三個類分別是:M層對應MainModel,P層對應MainPresenter,V層對應MainActivity。
我們來編寫MainPresenter類中的代碼,首先需要讓它實現MainContract類中的Presenter接口,然后為它設置兩個屬性,一個是Model,一個是View,在構造方法中傳入View,並初始化Model,最后實現Presenter接口中的方法並調用Model中的對應方法實現。MainPresenter類中的代碼如下:
public class MainPresenter implements MainContract.Presenter { private MainContract.Model model; private MainContract.View view; public MainPresenter(MainContract.View view) { this.view = view; this.model = new MainModel(); } @Override public void onButtonClicked(Context context, String text) { model.onButtonClicked(context, text); } }
接下來是MainModel類中的代碼了。MVP中的所有具體邏輯實現的代碼都是在Model層中編寫的,因此在MainModel實現Model接口的onButtonClicked()方法中,我們按照需求彈出一個Toast即可。代碼如下:
public class MainModel implements MainContract.Model { @Override public void onButtonClicked(Context context, String text) { Toast.makeText(context, text, Toast.LENGTH_SHORT).show(); } }
最后就是View層的編寫了。上面說過,View層的實現類就是Activity,View層中需要持有一個Presenter的引用,View層中的所有操作都調用Presenter層中對應的方法,而Presenter層都是調用Model層的代碼,因此View層就算是間接的調用了Model層的代碼。MainActivity中的代碼如下:
public class MainActivity extends AppCompatActivity implements MainContract.View { private MainPresenter presenter = new MainPresenter(MainActivity.this); @InjectView(R.id.btn) protected Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化ButterKnife ButterKnife.inject(MainActivity.this); } @OnClick(R.id.btn) protected void click() { onButtonClicked("Button Clicked!!!!"); } @Override public void onButtonClicked(String text) { presenter.onButtonClicked(MainActivity.this, text); } }
到此為止,MVP的一個簡單的DEMO就完成了。MVP只是一種思路,每個人都有每個人的理解,因此架構的搭建會有所不同,但整體的目標是不變的,那就是讓Activity中的View層和Controller層分離開來,減少Activity中的代碼。
當然,MVP模式也有缺點,那就是每創建一個Activity,就需要再創建Contract、Model、Presenter三個類,會大大增加項目中的類的個數。
