歡迎關注我們,一起討論技術,掃描和長按下方的二維碼可快速關注我們。或搜索微信公衆號:JANiubility。
公衆號:JANiubility
最近在做公司項目的重構工作,主要重構點包括:
-
網絡請求框架由 HttpURLConnection + Handler 改爲 Retrofit + OkHttp + RxJava
-
事件通知由 安卓廣播 改爲 RxBus
-
圖片加載框架由 ImageLoader 改爲 Glide
-
代碼優化(瘦身,內存泄漏分析等)
-
將傳統 Activity 作爲 God Object 的 MVC 模式 改爲兼容原代碼的MVP模式
-
…
這是現在Android應用的主流架構:
Retrofit + OkHttp + RxJava + MVP
今天主要分享一下,如何將原項目轉爲MVP模式,並且兼容原有代碼。有空的話再分享其他模塊的重構經過。
MVP,全稱 Model-View-Presenter,其中Presenter解耦了Model與View,使得每個模塊的職責更加單一,Model負責獲取數據,View只關心視圖的繪製,Presenter關聯Model和View處理業務邏輯。
與傳統的MVC模式相比更加易於維護和排查漏洞,以及更容易編寫單元測試。
MVP模式也有一些缺點,比如類文件數目增加,每一層都需要接口與實現類,在系統相對不是特別複雜的情況下可以捨棄Model層與Presenter接口,MVP模式並沒用固定的模板,其中每一層的實現可以根據各自的業務場景做相應的調整。
並不是所有的頁面都需要使用MVP模式,相對簡單的頁面完全可以用原來的實現模式。
推薦幾篇關於MVP模式介紹比較全面的文章:
Android MVP 詳解(上)
http://www.jianshu.com/p/9a6845b26856Android MVP 詳解(下)
http://www.jianshu.com/p/0590f530c617Google 官方Android MVP架構實踐
http://blog.csdn.net/u011459799/article/details/51360882
下面正式開始,如有不妥之處,請老司機多多指教。
首先定義各層的接口,各層之間通過接口耦合:
-
View接口
public interface IView{ }
2.Model接口:
public interface IModel { }
3.Presenter 接口:
public interface IPresenter<T extends IView> {
void attachView(T view);
void start();
void detachView();
}
實現一下Ipresenter接口中簡單的邏輯:BasePresenter ,使用時直接繼承該類:
public abstract class BasePresenter<T extends IView,M extends IModel> implements IPresenter<T> {
protected static final String TAG = "BasePresenter";
protected T mView;
protected M mModel;
@Override
public void attachView(T view) {
mView = view;
}
@Override
public void detachView() {
mView = null;
}
public boolean isViewAttached() {
return mView != null;
}
public T getView() {
return mView;
}
public M getModel() {
return mModel;
}
}
到目前爲止MVP模式的基礎代碼已經編寫完成了,下面的介紹是爲了兼容原代碼。
現有項目中一般都會有一個BaseActivity,爲了方便在Activity中使用MVP模式,以及不影響現有頁面,再次實現一個IViewActivity繼承BaseActivity封裝MVP相關邏輯。如果要使用MVP模式則繼承IViewActivity,否則繼承BaseActivity,從而兼容了原有代碼,並且引入MVP模式開發新頁面。
下面是IViewActivity:
/**
* Mvp base activity
* Created by qiulinmin on 16-9-22.
*/
public abstract class IViewActivity<P extends IPresenter> extends BaseActi implements IView {
protected P mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = onLoadPresenter();
getPresenter().attachView(this);
initEventAndData();
if(getPresenter() != null) {
getPresenter().start();
}
}
public P getPresenter() {
return mPresenter;
}
@Override
protected void onDestroy() {
if (getPresenter() != null) {
getPresenter().detachView();
}
super.onDestroy();
}
protected abstract P onLoadPresenter();
protected abstract void initViews(Bundle savedInstanceState);
protected abstract void initEventAndData();
}
在 onLoadPresenter() 中初始化Presenter,初始化工作完成之後會調用IPresenter.start()方法轉到Present層處理業務邏輯。
以上關於MVP模式所有代碼都已經編寫好了。
使用時爲了減少類文件數目,可以寫一個Contract接口來統一管理每一層的接口,例如:
public interface DemoContract {
interface View extends IView {
}
interface Model extends IModel {
}
interface Presenter extends IPresenter<View> {
}
}
最後實現present,model接口,
public class DemoPresenter extends BasePresenter<DemoContract.View, DemoContract.Model> implements DemoContract.presenter { }
public class DemoModel implements DemoContract.Model { }
在DemoPresenter的構造器中需要初始化DemoModel,因爲是接口耦合的,在初始化DemoModel時完全可以替換成其他的實現。
最後的最後Activity作爲View層實現DemoContract.View:
public class DemoActivity extends IViewActivity<DemoContract.Presenter> implements DemoContract.View {
protected DemoContract.Presenter onLoadPresenter() {
return new DemoPresenter();
}
protected void initViews(Bundle savedInstanceState) {
//略...
}
protected void initEventAndData() {
//略...
}
}
Activity頓時感到如釋重負,它只要關心如何繪製UI,把邏輯處理的工作丟給了Presenter,同時存取數據的活交給了Model,Presenter 通過 Model 獲取數據,通知 View 繪製界面。而且他們之間又是通過接口耦合的,只要替換掉實現,就能方便的改變需求,Presenter實現中可以不包含任何Android相關的代碼,因爲是純Java代碼,所以可以方便的使用JUnit配合Mokito進行單元測試。
源碼及Demo下載關注下方公衆號後領取
更多學習資料點擊下面二維碼關注公衆號後領取
Java和Android架構
歡迎關注我們,一起討論技術,掃描和長按下方的二維碼可快速關注我們。或搜索微信公衆號:JANiubility。
公衆號:JANiubility