準備用MVP框架搭建一個自己的項目,之前的項目有用到過,但都是公司的同事搭建好的,現在自己搭建一個。
搭建之前先來了解一下MVP。
1、什麼是MVP
M(Model)負責數據的請求,解析,過濾等數據操作。
V(View)負責處理UI,通常以Activity Fragment的形式出現。
P(Presenter)View Model中間件,交互的橋樑。
2、MVP的優點
分離了UI邏輯和業務邏輯,降低了耦合。
Activity只處理UI相關操作,代碼變得更加簡潔。
UI邏輯和業務邏輯抽象到接口中,方便閱讀及維護。
把業務邏輯抽到Presenter中去,避免複雜業務邏輯造成的內存泄漏。
3、MVP與MVC的比較
MVP的優點:
1)複雜的邏輯處理放在presenter進行處理,減少了activity的臃腫。
2)M層與V層完全分離,修改V層不會影響M層,降低了耦合性。
3)可以將一個Presenter用於多個視圖,而不需要改變Presenter的邏輯。
3)P層與V層的交互是通過接口來進行的,便於單元測試。
MVP的缺點:
由於對視圖的渲染放在了Presenter中,所以視圖和Presenter的交互會過於頻繁,視圖需要改變,一般presenter也需要跟着改變.
/******************************************************************************************************************/
MVC的優點:
1):分工明確,各司所職。
2):一定程度上降低了代碼間的耦合性。
MVC的缺點:
1):隨着界面及其邏輯的複雜度不斷提升,Activity類的職責不斷增加,以致變得龐大臃腫。
2):視圖和控制器間過於緊密的聯繫,妨礙了各自的重用。
搭建過程
創建基類
1.對View進行封裝,主要處理顯示加載框、請求成功、請求失敗等操作
package com.lyw.modulemvp.base;
import android.content.Context;
/**
* 功能描述:
* Created on 2020/6/29.
* @author lyw
*/
public interface IBaseView {
/**
* 顯示加載框
*/
void showLoading();
/**
* 隱藏加載框
*/
void dismissLoading();
/**
* 空數據
*
* @param tag TAG
*/
void onEmpty(Object tag);
/**
* 錯誤數據
*
* @param tag TAG
* @param errorMsg 錯誤信息
*/
void onError(Object tag, String errorMsg);
/**
* 上下文
*
* @return context
*/
Context getContext();
}
2.對Presenter封裝 ,爲了避免持有View的Presenter做耗時操作而引起的內存泄漏,我們的Presenter應該和宿主Activity/Fragment同創建、同銷燬。
package com.lyw.modulemvp.base;
import android.content.Context;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 功能描述:
* Created on 2020/6/29.
* @author lyw
*/
public abstract class BasePresenter<M extends IBaseModel, V extends IBaseView> {
private V mView;
private M mModel;
private WeakReference<V> weakReference;
/**
* 綁定View
*/
@SuppressWarnings("unchecked")
public void attachView(V view) {
weakReference = new WeakReference<>(view);
mView = (V) Proxy.newProxyInstance(
view.getClass().getClassLoader(),
view.getClass().getInterfaces(),
new MvpViewHandler(weakReference.get()));
if (this.mModel == null) {
this.mModel = createModule();
}
}
/**
* 解綁View
*/
public void detachView() {
this.mModel = null;
if (isViewAttached()) {
weakReference.clear();
weakReference = null;
}
}
/**
* 是否與View建立連接
*/
protected boolean isViewAttached() {
return weakReference != null && weakReference.get() != null;
}
protected V getView() {
return mView;
}
protected M getModule() {
return mModel;
}
protected Context getContext() {
return getView().getContext();
}
protected void showLoading() {
getView().showLoading();
}
protected void dismissLoading() {
getView().dismissLoading();
}
/**
* 通過該方法創建Module
*/
protected abstract M createModule();
/**
* 初始化方法
*/
public abstract void start();
/**
* View代理類 防止 頁面關閉P異步操作調用V 方法 空指針問題
*/
private class MvpViewHandler implements InvocationHandler {
private IBaseView mvpView;
MvpViewHandler(IBaseView mvpView) {
this.mvpView = mvpView;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//如果V層沒被銷燬, 執行V層的方法.
if (isViewAttached()) {
return method.invoke(mvpView, args);
} //P層不需要關注V層的返回值
return null;
}
}
}
3、對Activity的封裝,Fragment封裝同理,通過泛型規定Presenter,並且暴露抽象方法createPresenter()給子類來創建Presenter,基類實現BaseView中的公共方法,減少子類代碼的冗餘。
package com.lyw.modulemvp.base;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.View;
/**
* 功能描述:Mvp Activity基類
* Created on 2020/6/29.
* @author lyw
*/
public abstract class BaseMvpActivity<P extends BasePresenter> extends BaseActivity implements IBaseView {
protected P presenter;
private Context mContext;
@SuppressWarnings("unchecked")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//創建present
presenter = createPresenter();
if (presenter != null) {
presenter.attachView(this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (presenter != null) {
presenter.detachView();
presenter = null;
}
}
@Override
public void showLoading() {
if (mLoadingLayout != null) {
mLoadingLayout.setVisibility(View.VISIBLE);
}
}
@Override
public void dismissLoading() {
if (mLoadingLayout != null) {
mLoadingLayout.setVisibility(View.GONE);
}
}
@Override
public void onEmpty(Object tag) {
}
@Override
public void onError(Object tag, String errorMsg) {
}
@Override
public Context getContext() {
return mContext;
}
/**
* 創建Presenter
*/
protected abstract P createPresenter();
}
子類的具體實現會在後面的demo完善,DEMO地址