1. 程式人生 > >Android跟我一起來開發--微影之架構篇

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幹嘛的,各個引用啥時候銷燬啊等等(哇咔咔,憋了這這麼久憋出來的把自己都快搞暈了,甩甩臉,今天就到這了,下篇再針對以上問題進行補充講解,不對,自我解釋。。。)



下載地址:微影
github:Ghost
歡迎大家下載和Star