MVP模式是什麼?MVP 是從經典的模式MVC演變而來,它們的基本思想有相通的地方:Controller/Presenter負責邏輯的處理,Model提供數據,View負責顯示。android
爲何會出現MVP模式呢?這是由於原有的MVC模式有一些短板。好比在android開發中,activity充當着MVC中Controller的角色,可是在實際開發中處理view的邏輯和角色。當業務界面複雜時個人activity會顯得很龐大。因而出現了MVP模式,它新增了一個Presenter角色用於處理數據和界面的模型以及邏輯,Activity僅僅用於展現界面和用戶交互,這樣就解決了MVC中角色不清的局面。
因此,MVP與MVC的重大區別:在MVP中View並不直接使用Model,它們之間的通訊是經過Presenter (MVC中的Controller)來進行的,全部的交互都發生在Presenter內部,而在MVC中View會直接從Model中讀取數據而不是經過 Controller。
在MVC裏,View是能夠直接訪問Model的!從而,View裏會包含Model信息,不可避免的還要包括一些業務邏輯。 在MVC模型裏,更關注的Model的不變,而同時有多個對Model的不一樣顯示,即View。因此,在MVC模型裏,Model不依賴於View,可是View是依賴於Model的。不只如此,由於有一些業務邏輯在View裏實現了,致使要更改View也是比較困難的,至少那些業務邏輯是沒法重用的。git
MVC模式結構github
MVP模式結構mvc
小節:MVP模式至關於在MVC模式中又加了一個Presenter用於處理模型和邏輯,將View和Model徹底獨立開,在android開發中的體現就是activity僅用於顯示界面和交互,activity不參與模型結構和邏輯,app
谷歌官網給了咱們一個MVP模式實戰的例子,它是一個相似記事本的app,源碼地址在:https://github.com/googlesamples/android-architecture
官方案例的框架圖以下:
框架
看完源碼後發現其不適合初學者理解,因而我本身寫了一個demo方便你們理解。
demo源碼地址:https://github.com/halibobo/AndroidMvpExample
源碼主要類的結構以下dom
下面來看源碼
View層對應的是MainActivity,它繼承了抽離出View全部操做方法的接口OperationViewiphone
/** * *Created by su on 2016/6/22. */ public interface OperationView { void showCreatingPhone(); void showPhoneCountChange(); void showNoPhone(); void showFactoryBusy(); void showCreatedPhone(); }
MainActivity具體對每一個操做進行了具體的實現ide
public class MainActivity extends AppCompatActivity implements OperationView { private ListView listView; private Button btnCreate; private PhonePresenter phonePresenter; private ProgressDialog mLoadingDialog; ArrayAdapter<Phone> arrayAdapter; private Toast toast; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); PhoneFactory phoneFactory = new PhoneFactory(); phoneFactory.createPhone("nokia",555); phonePresenter = new PhonePresenter(phoneFactory, this); btnCreate = (Button) findViewById(R.id.btnCreate); listView = (ListView) findViewById(R.id.listView); arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, phoneFactory.getPhonesList()); btnCreate.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { phonePresenter.addPhone(new Phone("iphone", 4000+ new Random().nextInt(1000))); } }); listView.setAdapter(arrayAdapter); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { phonePresenter.removePhone(position); } }); } @Override public void showCreatingPhone() { mLoadingDialog = new ProgressDialog(this); mLoadingDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); mLoadingDialog.setMessage("工廠正在生產手機"); mLoadingDialog.setCancelable(true); mLoadingDialog.show(); } @Override public void showPhoneCountChange() { arrayAdapter.notifyDataSetChanged(); } @Override public void showNoPhone() { findViewById(R.id.noPhone).setVisibility(View.VISIBLE); } @Override public void showFactoryBusy() { showToast("工廠繁忙,請稍後再試!"); } @Override public void showCreatedPhone() { if (mLoadingDialog != null && mLoadingDialog.isShowing()) { mLoadingDialog.dismiss(); } mLoadingDialog = null; showToast("新生產出一臺手機!"); findViewById(R.id.noPhone).setVisibility(View.GONE); } private void showToast(String string) { if (toast == null) { toast = Toast.makeText(this, string, Toast.LENGTH_SHORT); }else{ toast.setText(string); } toast.show(); } }
Model層對應的是PhoneFactory,它處理和數據相關的一些簡單操做佈局
/** * Created by su on 2016/6/22. */ /** * 手機工廠類 */ public class PhoneFactory { private ArrayList<Phone> phonesList = new ArrayList<>(); public void addPhone(Phone phone) { phonesList.add(phone); } public void removePhone(Phone phone) { phonesList.remove(phone); } public void removePhone(int index) { if (index >= 0 && index < phonesList.size()) { phonesList.remove(index); } } public void createPhone(String name, double price) { Phone phone = new Phone(name, price); phonesList.add(phone); } public ArrayList<Phone> getPhonesList() { return phonesList; } public int getPhoneCounts() { return phonesList.size(); } }
下面是最爲重要的Presenter層 對應代碼中的PhonePresenter,它處理界面邏輯和數據模型等,源碼以下:
public class PhonePresenter implements TaskPresenter{ private final PhoneFactory phoneFactory; private final OperationView operationView; private static final long createPhoneTime = 2000; private static final int msgWhat = 0x102; public PhonePresenter(@NonNull PhoneFactory phoneFactory, @NonNull OperationView operationView) { this.phoneFactory = phoneFactory; this.operationView = operationView; } @Override public void addPhone(Phone phone) { operationView.showPhoneCountChange(); if (mHandler.hasMessages(msgWhat)) { operationView.showFactoryBusy(); return; } Message message = new Message(); message.what = msgWhat; message.obj = phone; mHandler.sendMessageDelayed(message, createPhoneTime); operationView.showCreatingPhone(); } @Override public void removePhone(int index) { phoneFactory.removePhone(index); if (phoneFactory.getPhoneCounts() <= 0) { operationView.showNoPhone(); } operationView.showPhoneCountChange(); } @Override public void removePhone(Phone phone) { } public ArrayList<Phone> getPhones() { ArrayList<Phone> phones = phoneFactory.getPhonesList(); if (phones.isEmpty()) { operationView.showNoPhone(); } return phones; } private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); phoneFactory.addPhone((Phone)msg.obj); operationView.showCreatedPhone(); operationView.showPhoneCountChange(); } }; }
運行效果圖以下:
使用MVP模式會使得代碼多出一些接口可是使得代碼邏輯更加清晰,尤爲是在處理複雜界面和邏輯時,咱們能夠對同一個activity將每個業務都抽離成一個Presenter,這樣代碼既清晰邏輯明確又方便咱們擴展。固然若是咱們的業務邏輯自己就比較簡單的話使用MVP模式就顯得,沒那麼必要。因此咱們不須要爲了用它而用它,具體的仍是要要業務須要