**MVP模式結構** - Model: 業務邏輯和實體模型 - View:用戶交互和視圖顯示,在android中對應activity - Presenter: 負責完成View於Model間的邏輯和交互 ...
android MVP模式介紹與實戰
描述
MVP模式是什麼?MVP 是從經典的模式MVC演變而來,它們的基本思想有相通的地方:Controller/Presenter負責邏輯的處理,Model提供數據,View負責顯示。
MVC和MVP的區別?
為什麼會出現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也是比較困難的,至少那些業務邏輯是無法重用的。
MVC模式結構
- Model 業務邏輯和實體模型
- Controller 對應Activity
- View 視圖以及佈局文件
MVP模式結構
- Model: 業務邏輯和實體模型
- View:用戶交互和視圖顯示,在android中對應activity
- Presenter: 負責完成View於Model間的邏輯和交互
小節:MVP模式相當於在MVC模式中又加了一個Presenter用於處理模型和邏輯,將View和Model完全獨立開,在android開發中的體現就是activity僅用於顯示界面和交互,activity不參與模型結構和邏輯,
實戰
谷歌官網給了我們一個MVP模式實戰的例子,它是一個類似記事本的app,源碼地址在:https://github.com/googlesamples/android-architecture
官方案例的框架圖如下:
看完源碼後發現其不適合初學者理解,於是我自己寫了一個demo方便大家理解。
demo源碼地址:https://github.com/halibobo/AndroidMvpExample
源碼主要類的結構如下
下麵來看源碼
View層對應的是MainActivity,它繼承了抽離出View所有操作方法的介面OperationView
/**
* *Created by su on 2016/6/22.
*/
public interface OperationView {
void showCreatingPhone();
void showPhoneCountChange();
void showNoPhone();
void showFactoryBusy();
void showCreatedPhone();
}
MainActivity具體對每個操作進行了具體的實現
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模式就顯得,沒那麼必要。所以我們不需要為了用它而用它,具體的還是要要業務需要
謝謝大家
demo地址在:https://github.com/halibobo/AndroidMvpExample