淺談Android中MVP模式用於實際專案中的問題與優化

NO IMAGE

學習MVP不算久,前段時間才把公司的兩個專案完全轉換為MVP模式,改了下來,略有心得,給大家分享一下。

才開始學習使用MVP時,看到大家說了很多MVP的優點,程式碼複用,條理清晰等等。不過我改下來發現,MVP在我看來,最大的優點還是程式碼解耦,邏輯清晰,至於程式碼複用,暫時沒有感覺很好用,除非是介面和邏輯基本一樣的,不然想要複用,其實不太現實。

MVP的優點很明顯,缺點其實也很明顯,明顯專案會多出許多類,增加了專案的複雜程度,而且像某些邏輯及其簡單,事件較少的介面,使用MVP實際上反而是累贅,明明用MVC也就幾十行程式碼的事,改成MVP多了好多個類,反而感覺不划算,改需求時又要翻閱好多個類。因此,我建議大家,如果你的某個介面極其簡單,其實就不要用MVP了,MVP是邏輯越複雜,優勢越明顯,邏輯簡單時,反而不如MVC好用,希望大家不要為了用MVP而用MVP。

下面來談談文章主題,MVP的優化問題,最開始採用網上大家的寫法,發現程式碼的複用性不好,有些邏輯類似的程式碼,基本上每個presenter 和model都要重新寫,於是想到使用Base類的方法,把某些共有的方法抽離以達到程式碼的複用性,類似於BaseActivity。

舉個例子比如網路請求,在MVC中通常是把網路請求封裝在BaseActivity中,不過既然是MVP,網路請求自然應該封裝在Model裡面啦

public abstract class BaseActivityModel implements IPublicModel {
//網路連線模式,當一個頁面含有多個網路請求時,通過傳入不同的模式,選擇相應的載入引數
public static final int MODE_ONE=1;
public static final int MODE_TWO=2;
public static final int MODE_THREE=3;
//網路連線工具介面類
protected InternetConnect mConnect;
/**
     * @param mode 請求模式
     * @param intent 上個頁面傳遞過來的intent
     * @param i 請求回撥
     * @param parameter 請求的一些引數
     */
    @Override
public void requestData (int mode, Intent intent, JsonI i, String... parameter) {
HashMap<String, String> map = new HashMap<>();
JsonBean.Payload payload=new JsonBean.Payload();
mConnect.loadParameter(intent,mode,payload,map,parameter);//載入引數,由子類實現
map.put("payload", VolleyConnect.getGson().toJson(payload));
VolleyConnect.getInVolleyConnect().getServiceMsg( map,i);//封裝Volley,傳入引數以及回撥介面
}
/**
     * 設定網路請求
     */
    @Override
public void setMConnect (InternetConnect mConnect) {
this.mConnect=mConnect;
}
}

同樣的共有的方法和欄位抽象出presenter的基類

public abstract class BaseActivityPresenter<T extends IPublicView, E extends IPublicModel> implements IPublicPresenter {
protected T view;
protected E model;
protected RequestResult mRequestResult;
protected Handler mHandler;
public BaseActivityPresenter (T view) {
this.view = view;
Type type = getClass().getGenericSuperclass();//使用反射例項化Model
Type trueType = ((ParameterizedType) type).getActualTypeArguments()[1];
try {
this.model = ((Class<E>) trueType).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
new TimeCount(200, 50, new ITimeCount() {
@Override
public void isRuning (long millisUntilFinished) {
}
@Override
public void isFinish () {
init();//載入子類方法,延時200毫秒載入
}
}).start();
}
/*
設定網路請求回撥
*/
public void setRequestResult (RequestResult requestResult) {
mRequestResult = requestResult;
}
/*
獲取view的handler,需要傳入一個回撥介面
*/
public void setHandler (IHandler handlerI) {
mHandler = view.exposeHandler(handlerI);
}
@Override
public void requestData (final int mode, String... parameter) {
view.setLoading(true);
model.requestData(mode, view.exposeIntent(), new JsonI() {
@Override
public void notice (JsonBean bean) {
//                if (bean.getStatus().equals("0")) {
//                    mRequestResult.requestDataSuccess(mode,bean);
//                }else{
//                    mRequestResult.requestDataFail(mode,bean);
//                }
view.setLoading(false);
}
@Override
public void notice (int error) {
view.showError(error);
}
}, parameter);
}
}

這樣我們就可以更加簡單方便的使用MVP模式了,下面是使用示例

public class LoginPresenter extends BaseActivityPresenter<ILoginView,LoginModel> implements ILoginPresenter, RequestResult {
public LoginPresenter (ILoginView view) {
super(view);
}
@Override
public void init () {
setRequestResult(this);
}
@Override
public void requestDataSuccess (int mode, JsonBean bean) {
}
@Override
public void requestDataFail (int mode, JsonBean bean) {
}
}

可以看到,LoginPresenter不再需要去寫model欄位和網路請求邏輯,通過泛型,可以自動建立model,而網路請求,僅僅需要設定對應的回撥就可以噠。

總結,這樣做進一步降低了程式碼耦合,方便以後程式碼維護,而且整個MVP感覺更加簡單。