所謂MVP(Model-View-Presenter)模式。是將APP的結(jié)構(gòu)分為三層:
view - UI顯示層
view 層主要負(fù)責(zé):
- 提供UI交互
- 在presenter的控制下修改UI。
- 將業(yè)務(wù)事件交由presenter處理。
注意. View層不存儲(chǔ)數(shù)據(jù),不與Model層交互。
presenter - 邏輯處理層
presenter 層主要負(fù)責(zé):
- 對(duì)UI的各種業(yè)務(wù)事件進(jìn)行相應(yīng)處理。也許是與Model層交互,也許自己進(jìn)行一些計(jì)算,也許控制后臺(tái)Task,Servic
- 對(duì)各種訂閱事件進(jìn)行響應(yīng),修改UI。
- 臨時(shí)存儲(chǔ)頁面相關(guān)數(shù)據(jù)。
注意. Presenter內(nèi)不出現(xiàn)View引用。
model - 數(shù)據(jù)層
model層主要負(fù)責(zé):
- 從網(wǎng)絡(luò),數(shù)據(jù)庫,文件,傳感器,第三方等數(shù)據(jù)源讀寫數(shù)據(jù)。
- 對(duì)外部的數(shù)據(jù)類型進(jìn)行解析轉(zhuǎn)換為APP內(nèi)部數(shù)據(jù)交由上層處理。
- 對(duì)數(shù)據(jù)的臨時(shí)存儲(chǔ),管理,協(xié)調(diào)上層數(shù)據(jù)請(qǐng)求。
如圖示,里面的activity,presenter,model均為例子:

將復(fù)雜的功能分割為各層內(nèi)的小問題。各層內(nèi)功能單一。這樣易于功能修改拓展與Debug。
解耦的設(shè)計(jì),獨(dú)立的模塊,更有利于分工開發(fā)與測(cè)試。
Activity的異常重啟
Activity會(huì)在少數(shù)情況下被系統(tǒng)重啟:
當(dāng)用戶旋轉(zhuǎn)屏幕
在后臺(tái)時(shí)內(nèi)存不足
改變語言設(shè)置
attache 一個(gè)外部顯示器等。
正確的方式應(yīng)該是:
Presenter與Activity的綁定關(guān)系應(yīng)由靜態(tài)類管理。而不是由Activity管理。當(dāng)Activity意外重啟時(shí)Presenter不應(yīng)重啟。Activity重啟時(shí),Presenter與Activity重新綁定,根據(jù)數(shù)據(jù)恢復(fù)Activity狀態(tài)。
而當(dāng)Activity真正銷毀時(shí)。對(duì)應(yīng)Presenter才應(yīng)該跟隨銷毀。
當(dāng)內(nèi)存不足時(shí),Activity被銷毀其實(shí)是整個(gè)進(jìn)程被銷毀。所以Presenter也無能為力。還原時(shí)需要重建Presenter。
生命周期
Activity是一個(gè)上帝類,其實(shí)不適合作為View。所以有些MVP方案將Activity作為Presenter。最主要在于他的生命周期牽扯太多邏輯處理業(yè)務(wù)。這些由Presenter負(fù)責(zé)的話情況可以改善很多。我建議將在頂級(jí)父類中將activity的生命周期在Presenter中實(shí)現(xiàn)一遍,然后生命周期有關(guān)的業(yè)務(wù)邏輯直接由Presenter來實(shí)現(xiàn)。
Model的初始化
Model不僅僅是javabean。Model是負(fù)責(zé)提供各類數(shù)據(jù)模型。在此基礎(chǔ)上我將Model拓展為數(shù)據(jù)層提供數(shù)據(jù)交互。將javabean單獨(dú)為數(shù)據(jù)層的一部分。
Model層的各個(gè)Model一般使用單例。這樣的好處在于這個(gè)唯一對(duì)象可以管理一些數(shù)據(jù)供所有上層使用。
Model的單例對(duì)象
public class UserModel extends AbsModel{
public static UserModel getInstance() {
return getInstance(UserModel.class);
}
@Override
protected void onAppCreate(Context ctx) {
super.onAppCreate(ctx);
//初始化
}
public void login(String number,String password,DataCallback<UserDetail> callback){
//進(jìn)行登錄請(qǐng)求與回調(diào),并保存返回賬號(hào)
}
public void register(String tel,String password,String code,int gender,String nickname,StatusCallback callback){
//進(jìn)行注冊(cè)請(qǐng)求與回調(diào)
}
public void findPassword(String number,String code,String password,DataCallback<User> callback){
//進(jìn)行找回密碼請(qǐng)求與回調(diào)
}
public void certification(String number,String school,String realName,String stuCard,DataCallback<User> callback){
//進(jìn)行認(rèn)證請(qǐng)求與回調(diào)
}
public void LoginOut(){
//登出操作
}
}
既然Model層管理數(shù)據(jù),并且是單例。他就有初始化的需求,比如在APP啟動(dòng)時(shí)就請(qǐng)求數(shù)據(jù),記錄信息,開始一個(gè)后臺(tái)線程與服務(wù)器同步信息等。這些操作與Presenter無關(guān)。是數(shù)據(jù)層自發(fā)的的功能。所以需要在Application啟動(dòng)時(shí)進(jìn)行Model的初始化。
但又要注意不能在Application的onCreate()進(jìn)行過多操作,否則會(huì)啟動(dòng)時(shí)間過長。所以可考慮在啟動(dòng)時(shí)創(chuàng)建一個(gè)后臺(tái)線程,將即時(shí)性不強(qiáng)的初始化操作放到后臺(tái)線程。
Adapter的處理
對(duì)于Adapter是放在View好還是Presenter好,這個(gè)問題確實(shí)難以解決。但在使用解耦的ViewHolder后這個(gè)問題便很明了。視圖的創(chuàng)建與改變?nèi)蒝iewHolder管理。然后Adapter僅僅處理面向ViewHolder的邏輯。
然后ViewHolder屬于View,Adapter屬于Presenter。參考EasyRecyclerView
Adapter:
public class PersonAdapter extends RecyclerArrayAdapter<Person> {
public PersonAdapter(Context context) {
super(context);
}
@Override
public BaseViewHolder OnCreateViewHolder(ViewGroup parent, int viewType) {
return new PersonViewHolder(parent);
}
}
ViewHolder:
public class PersonViewHolder extends BaseViewHolder<Person> {
private TextView mTv_name;
private SimpleDraweeView mImg_face;
private TextView mTv_sign;
public PersonViewHolder(ViewGroup parent) {
super(parent,R.layout.item_person);
mTv_name = $(R.id.person_name);
mTv_sign = $(R.id.person_sign);
mImg_face = $(R.id.person_face);
}
@Override
public void setData(final Person person){
mTv_name.setText(person.getName());
mTv_sign.setText(person.getSign());
mImg_face.setImageURI(Uri.parse(person.getFace()));
}
}
Rx的參與
Rx訂閱發(fā)布模式在MVP中作用很大。可以極大簡(jiǎn)化層間通訊的處理。View向Presenter訂閱數(shù)據(jù)。Presenter可以向Model層訂閱數(shù)據(jù)。形成一個(gè)數(shù)據(jù)鏈。數(shù)據(jù)可以直接鏈?zhǔn)降竭_(dá)View層。優(yōu)雅易拓展。
Presenter
public class QuestionShowPresenter extends BeamDataActivityPresenter<QuestionShowActivity,Question> {
@Override
protected void onCreate(QuestionShowActivity view, Bundle savedState) {
super.onCreate(view, savedState);
QuestionModel.getInstance().getQuestion(1).subscribe(this);
}
}
View
public class QuestionShowActivity extends BeamDataActivity<QuestionShowPresenter,Question> {
@Override
public void setData(Question data) {
//顯示數(shù)據(jù)
}
@Override
public void setError(Throwable e) {
//顯示錯(cuò)誤
}
}
Beam
Beam是我做的一套基于MVP模式的快速開發(fā)框架。參考了nucleus。上面的示例代碼都是使用了這個(gè)(為方便復(fù)制的這個(gè)框架demo代碼.= =)。定義了一套開發(fā)規(guī)范。并提供了基于這套規(guī)范的Activity,F(xiàn)ragment,Presenter,Model等父類及控件和API等,完成APP開發(fā)過程中大量繁瑣工作。并進(jìn)行了一系列優(yōu)化。詳情看這里