
上一篇《Android跟我一起來開發(fā)--微影之開篇》中主要講述了一下寫這些博文的初衷,以及對項目中數(shù)據(jù)、架構(gòu)、框架(依賴)、目錄結(jié)構(gòu)作了一些簡單的介紹。接下來本文主要針對MVP架構(gòu)的個人理解做一個詳細的描述。當然還是站在巨人的肩膀上,我是先通讀了一下各位大神對官方mvp(基礎(chǔ)版)的分析,然后通過實際動手編寫來加深印象幫助自己更好理解。再次感謝各位大神的無私奉獻(ヽ(≧Д≦)ノ)。
說到mvp,我們不禁要思考這樣一個人生哲理:我是誰,我來自哪里,我要干什么?讓我們像剝洋蔥一層層剝開你外衣。mvp實際上就是mvc的一個變種,或者說是進化。在mvc中activity/fragment/view都是屬于view這一層,負責界面的繪制、與用戶交互,而實際上它既承擔了View的功能,同時也包含一些Controller的東西。不僅使代碼看起來臃腫,而且對于開發(fā)與維護來說都不太友好。通過把activity/fragment/view中的View和Controller剝離開來形成Presenter,專職做一些數(shù)據(jù)的處理、邏輯的控制等。在MVP中,M和V并沒有交集,兩人各自為政,互不干擾,通過P這個老好人作為中間人把三者聯(lián)系起來。通過以下兩張圖可以更清晰的理解mvc和mvp兩者之間的區(qū)別。(圖片來源)


為什么要使用mvp
- 分離了視圖邏輯和業(yè)務(wù)邏輯,降低了耦合
- Activity只處理生命周期的任務(wù),代碼變得更加簡潔
- 視圖邏輯和業(yè)務(wù)邏輯分別抽象到了View和Presenter的接口中去,提高代碼的可閱讀性
- Presenter和View被抽象成接口,可以有多種具體的實現(xiàn),所以方便進行單元測試
- 把業(yè)務(wù)邏輯抽到Presenter中去,避免后臺線程引用著Activity導(dǎo)致Activity的資源無法被系統(tǒng)回收從而引起內(nèi)存泄露和OOM
具體用法
說到具體的用法就先來po一張目錄結(jié)構(gòu)圖上來。
從結(jié)構(gòu)圖中不難看出,model中對應(yīng)mvp的M層,包含本地數(shù)據(jù)和遠程數(shù)據(jù)(Realm數(shù)據(jù)庫和網(wǎng)絡(luò));
base中主要是基礎(chǔ)類,其中BaseView中最主要的是setPresenter用于view持有presenter的引用。
void setPresenter(T presenter);

presenter包中包含了contract和presenter。其中contract是一個接口類,主要定義了繼承自baseView和basePresenter的接口,在這里聲明的接口可以一目了然,通過在V和P中進行實現(xiàn)可以使代碼更清晰簡潔易于管理。
public interface DiscoverContract {
interface View extends BaseView<Presenter> {
boolean isActive();
void showContent(VideoRes videoRes);
void refreshFaild(String msg);
void hidLoading();
}
interface Presenter extends BasePresenter {
void getData();
}
}
下邊是Presenter的實現(xiàn)類,可以看到在presenter的構(gòu)造方法中持有了對view的引用,同時調(diào)用了view的setPresenter方法綁定了自身使view持有了presenter的引用,這樣V和P形成了雙向引用的關(guān)系。
public class DiscoverPresenter extends RxPresenter implements DiscoverContract.Presenter {
DiscoverContract.View mView;
final String catalogId = "402834815584e463015584e53843000b";
......
public DiscoverPresenter(@NonNull DiscoverContract.View threeView) {
mView = Preconditions.checkNotNull(threeView);
mView.setPresenter(this);
}
@Override
public void getData() {
getNextVideos();
}
......
private void getNextVideos(){......}
}
在官方mvp(基礎(chǔ)版)中是以Fragment作為View的具體載體,我沒有這么做,我是以重寫LinearLayout的自定義view作為具體的view載體。來看一下view的代碼:
public class DiscoverView extends RootView<DiscoverContract.Presenter> implements DiscoverContract.View {
@BindView(R.id.title_name) ColorTextView titleName;
......
public DiscoverView(Context context) { super(context); }
public DiscoverView(Context context, AttributeSet attrs) { super(context, attrs); }
@Override
protected void getLayout() {
inflate(mContext, R.layout.fragment_discover_view, this);
}
@Override
public void setPresenter(DiscoverContract.Presenter presenter) { mPresenter = com.google.common.base.Preconditions.checkNotNull(presenter); }
@Override
public void showError(String msg) {
EventUtil.showToast(mContext, msg);
}
@Override
public void showContent(final VideoRes videoRes) {
......
}
}
下面在來看一下activity頁面,代碼是不是清爽多了,View只管view,Presenter只管邏輯。
public class CollectionActivity extends SwipeBackActivity {
@BindView(R.id.collect_view)
CollectionView collectView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collection);
unbinder = ButterKnife.bind(this);
mPresenter = new CollectionPresenter(collectView, 0);
}
}
至此整個過程就算走完了。看到這里你可能還是云里霧里,rootview是什么啊,rxpresenter干嘛的,各個引用啥時候銷毀啊等等(哇咔咔,憋了這這么久憋出來的把自己都快搞暈了,甩甩臉,今天就到這了,下篇再針對以上問題進行補充講解,不對,自我解釋。。。)

qq交流群:138485840
下載地址:微影
源碼地址:Ghost
歡迎大家下載和Star