Android跟我一起來開發--微影之架構篇
上一篇《Android跟我一起來開發--微影之開篇》中主要講述了一下寫這些博文的初衷,以及對專案中資料、架構、框架(依賴)、目錄結構作了一些簡單的介紹。接下來本文主要針對MVP架構的個人理解做一個詳細的描述。當然還是站在巨人的肩膀上,我是先通讀了一下各位大神對官方mvp(基礎版)的分析,然後通過實際動手編寫來加深印象幫助自己更好理解。再次感謝各位大神的無私奉獻(ヽ(≧Д≦)ノ)。
說到mvp,我們不禁要思考這樣一個人生哲理:我是誰,我來自哪裡,我要幹什麼?讓我們像剝洋蔥一層層剝開你外衣。mvp實際上就是mvc的一個變種,或者說是進化。在mvc中activity/fragment/view都是屬於view這一層,負責介面的繪製、與使用者互動,而實際上它既承擔了View的功能,同時也包含一些Controller的東西。不僅使程式碼看起來臃腫,而且對於開發與維護來說都不太友好。通過把activity/fragment/view中的View和Controller剝離開來形成Presenter,專職做一些資料的處理、邏輯的控制等。在MVP中,M和V並沒有交集,兩人各自為政,互不干擾,通過P這個老好人作為中間人把三者聯絡起來。通過以下兩張圖可以更清晰的理解mvc和mvp兩者之間的區別。
mvc
mvp
為什麼要使用mvp
- 分離了檢視邏輯和業務邏輯,降低了耦合
- Activity只處理生命週期的任務,程式碼變得更加簡潔
- 檢視邏輯和業務邏輯分別抽象到了View和Presenter的介面中去,提高程式碼的可閱讀性
- Presenter和View被抽象成介面,可以有多種具體的實現,所以方便進行單元測試
- 把業務邏輯抽到Presenter中去,避免後臺執行緒引用著Activity導致Activity的資源無法被系統回收從而引起記憶體洩露和OOM
具體用法
說到具體的用法就先來po一張目錄結構圖上來。
目錄結構圖
從結構圖中不難看出,model中對應mvp的M層,包含本地資料和遠端資料(Realm資料庫和網路);
base中主要是基礎類,其中BaseView中最主要的是setPresenter用於view持有presenter的引用。
void setPresenter(T presenter);
base
presenter包中包含了contract和presenter。其中contract是一個介面類,主要定義了繼承自baseView和basePresenter的介面,在這裡宣告的介面可以一目瞭然,通過在V和P中進行實現可以使程式碼更清晰簡潔易於管理。
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的實現類,可以看到在presenter的構造方法中持有了對view的引用,同時呼叫了view的setPresenter方法綁定了自身使view持有了presenter的引用,這樣V和P形成了雙向引用的關係。
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(基礎版)中是以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幹嘛的,各個引用啥時候銷燬啊等等(哇咔咔,憋了這這麼久憋出來的把自己都快搞暈了,甩甩臉,今天就到這了,下篇再針對以上問題進行補充講解,不對,自我解釋。。。)