原文出處:[高級MVP架構封裝演變全過程](http://blog.csdn.net/yulong0809/article/details/78622428)
本文重點是封裝一個高級MVP架構,會詳細的講解如何一步步從無到有的封裝成一個高級MVP架構過程。
眾所周知普通的MVP模式存在內存泄露、代碼冗余、界面意外關閉后在重建數據緩存等問題,本文最終封裝的成果為一一解決這些問題,而且在使用過程中盡量做到使用簡單而且可擴展,當然本文也只是提供了一種封裝思路而已,如果不能滿足你的需求還可以自行再進行擴展。
如果你覺得你不想看整個實現思路可以直接看最后的源碼,望給點個star鼓勵一下
[GitHub地址:https://github.com/ljqloveyou123](https://github.com/ljqloveyou123)
文章會以5個部分來整體優化封裝MVP,也是一個從無到有的過程
**一、不使用MVP的代碼**
**二、最簡單的MVP實現**
**三、解決MVP內存泄露**
**四、簡單抽象-解決MVP代碼冗余**
**五、高級抽象-使用注解、工廠模式、代理模式、策略模式整體解決代碼冗余、內存泄露、Presenter生命周期以及數據存儲問題**
不廢話了,進入正題。
場景:假如界面有一個按鈕,點擊后請求數據,然后成功后將返回的數據設置到一個Textview中
**一、不使用MVP的代碼,一般我們會這么寫**
~~~
public class MainActivity extends AppCompatActivity {
@FieldView(R.id.tv_text)
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewFind.bind(this);
}
//按鈕點擊事件
public void request(View view) {
clickRequest("101010100");
}
//發起請求
public void clickRequest(final String cityId) {
//請求接口
Retrofit retrofit = new Retrofit.Builder()
//代表root地址
.baseUrl("http://www.weather.com.cn/")
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiService apiService = retrofit.create(ApiService.class);
//請求
Call<WeatherBean> weatherBeanCall = apiService.requestWeather(cityId);
weatherBeanCall.enqueue(new Callback<WeatherBean>() {
@Override
public void onResponse(Call<WeatherBean> call, Response<WeatherBean> response) {
//請求成功
textView.setText(response.body().getWeatherinfo().toString());
}
@Override
public void onFailure(Call<WeatherBean> call, Throwable t) {
//請求失敗
}
});
}
}
~~~
上面的代碼是最原始的寫法,下面我們使用最簡單的MVP模式來改造這個代碼。
**二、最簡單的MVP實現**
思路如下:
1、首先我們先定義一個接口,用來規定針對這個界面邏輯View需要作出的動作的接口。
2、讓Activity實現這個接口中的方法,也就是V層
3、創建一個類,用來封裝之前的網絡請求過程,也就是M層
4、再創建一個類,用來處理M層和V層之間的通信,也就是P層
下面來實現一下:
1、首先我們先定義一個接口,用來規定針對這個界面邏輯View需要作出的動作的接口。
~~~
/**
* @author 劉鎵旗
* @date 2017/11/16
* @description V層接口,定義V層需要作出的動作的接口
*/
public interface RequestView1 {
//請求時展示加載
void requestLoading();
//請求成功
void resultSuccess(WeatherBean result);
//請求失敗
void resultFailure(String result);
}
~~~
2、讓Activity實現這個接口中的方法,也就是V層
~~~
/**
* 第二步:對應demo1
* 2,最簡單的mvp模式,
* 1.Activity需要實現v層接口
* 2.Persenter需要持有v層引用和m層引用
* 3.在實現類view中創建persenter
*
*/
public class MainActivity extends AppCompatActivity implements RequestView1 {
@FieldView(R.id.tv_text)
private TextView textView;
private RequestPresenter1 presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewFind.bind(this);
//創建Presenter
presenter = new RequestPresenter1(this);
}
//點擊事件
public void request(View view) {
presenter.clickRequest("101010100");
}
//請求時加載
@Override
public void requestLoading() {
textView.setText("請求中,請稍后...");
}
//請求成功
@Override
public void resultSuccess(WeatherBean result) {
//成功
textView.setText(result.getWeatherinfo().toString());
}
//請求失敗
@Override
public void resultFailure(String result) {
//失敗
textView.setText(result);
}
}
~~~
3、創建一個類,用來封裝之前的網絡請求過程,也就是M層
~~~
/**
* @author 劉鎵旗
* @date 2017/11/16
* @description M層 數據層
*/
public class RequestMode1 {
private static final String BASE_URL = "http://www.weather.com.cn/";
//http://www.weather.com.cn/data/cityinfo/101010100.html
public void request(String detailId, Callback<WeatherBean> callback){
//請求接口
Retrofit retrofit = new Retrofit.Builder()
//代表root地址
.baseUrl(BASE_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiService apiService = retrofit.create(ApiService.class);
//請求
Call<WeatherBean> weatherBeanCall = apiService.requestWeather(detailId);
weatherBeanCall.enqueue(callback);
}
}
~~~
4、再創建一個類,用來處理M層和V層之間的通信,也就是P層
~~~
/**
* @author 劉鎵旗
* @date 2017/11/16
* @description P層
* 特點:需要持有M層和V層
*/
public class RequestPresenter1 {
private final RequestView1 mRequestView;
private final RequestMode1 mRequestMode;
public RequestPresenter1(RequestView1 requestView) {
this.mRequestView = requestView;
this.mRequestMode = new RequestMode1();
}
public void clickRequest(final String cityId){
//請求時顯示加載
mRequestView.requestLoading();
//模擬耗時,可以展示出loading
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mRequestMode.request(cityId, new Callback<WeatherBean>() {
@Override
public void onResponse(Call<WeatherBean> call, Response<WeatherBean> response) {
mRequestView.resultSuccess(response.body());
}
@Override
public void onFailure(Call<WeatherBean> call, Throwable t) {
mRequestView.resultFailure(Log.getStackTraceString(t));
}
});
}
},1000);
}
}
~~~
好了,上面的4步就是最基本的MVP模式的使用了,可是這樣寫會內存泄露,因為如果在網絡請求的過程中Activity就關閉了,Presenter還持有了V層的引用,也就是MainActivity,就會內存泄露。
**三、解決MVP內存泄露**
下面就來解決這個問題,我們將P層和V層的關聯抽出兩個方法,一個綁定,一個解綁,在需要的時候進行綁定V層,不需要的時候進行解綁就可以了。我們只需要修改上面Presenter中的構造代碼,不需要在構造中傳遞V層了,然后再寫一個綁定和解綁的方法,最后修改Activity創建Presenter時進行綁定,在onDestroy中進行解綁。
修改后的Presenter:
~~~
/**
* @author 劉鎵旗
* @date 2017/11/16
* @description
*/
public class RequestPresenter2 {
private RequestView2 mView;
private RequestMode2 mMode;
public RequestPresenter2() {
mMode = new RequestMode2();
}
public void clickRequest(final String cityId) {
if(mView != null){
mView.requestLoading();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mMode.request(cityId, new Callback<WeatherBean>() {
@Override
public void onResponse(Call<WeatherBean> call, Response<WeatherBean> response) {
if(mView != null){
mView.resultSuccess(response.body());
}
}
@Override
public void onFailure(Call<WeatherBean> call, Throwable t) {
if(mView != null){
mView.resultFailure(Log.getStackTraceString(t));
}
}
});
}
},1000);
}
}
/**
* 綁定
* @param view
*/
public void attach( RequestView2 view) {
this.mView = view;
}
/**
* 解除綁定
*/
public void detach() {
mView = null;
}
/**
* 取消網絡請求
*/
public void interruptHttp(){
mMode.interruptHttp();
}
}
~~~
修改后的MainActivity:
~~~
/**
* 第三步:對應demo2
* 上面的問題:
* 1.是會內存泄露,因為persenter一直持有Activity,如果一個發了一個請求,但是網絡有點慢,這個時候退出Activity,那么請求回來后還是會調用
* Activity的回調方法,這里還是因為一直持有的問題
* 2.如果已經退出了當前界面,這個請求也沒有用了,這個時候我們可以斷開請求
* <p>
* 解決問題:
* 1.增加綁定和解綁的方法來解決內存泄露和退出后還會回調的問題
* 2、增加斷開網絡連接的方法
*/
public class MainActivity extends AppCompatActivity implements RequestView2 {
@FieldView(R.id.tv_text)
private TextView textView;
private RequestPresenter2 presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewFind.bind(this);
presenter = new RequestPresenter2();
presenter.attach(this);
}
public void request(View view) {
presenter.clickRequest("101010100");
}
@Override
public void requestLoading() {
textView.setText("請求中,請稍后...");
}
@Override
public void resultSuccess(WeatherBean result) {
//成功
textView.setText(result.getWeatherinfo().toString());
}
@Override
public void resultFailure(String result) {
//失敗
textView.setText(result);
}
@Override
protected void onDestroy() {
super.onDestroy();
presenter.detach();
presenter.interruptHttp();
}
}
~~~
這樣我們就解決了內存泄露的問題,但是這樣還是不完美,應用中肯定不可能只有一個模塊,每個模塊都對應著一個V層和P層,那這樣的話每個Presenter中都要定義綁定和解綁的方法,而Activity中對應的也要調用這綁定和解綁的兩個方法,代碼冗余。
**四、簡單抽象-解決MVP代碼冗余**
針對這個問題我們可以抽取出一個基類的Presenter和一個基類的Activity來做這個事情,讓子類不用在寫這些重復的代碼。但是問題又來了,**既然是基類,肯定不止有一個子類來繼承基類,那么也就是說子類當中定義的View接口和需要創建的Presenter都不相同,我們肯定在基類當中不能寫死吧,那就使用泛型來設計**。
**思路**:
1. 創建一個基類View,讓所有View接口都必須實現,**這個View可以什么都不做只是用來約束類型**的
2. 創建一個基類的Presenter,在**類上規定View泛型**,然后**定義綁定和解綁的抽象方法**,讓子類去實現,對外在提供一個獲取View的方法,
讓子類直接通過方法來獲取View
3. 創建一個基類的Activity,**聲明一個創建Presenter的抽象方法(abstract P createPresenter())**,**因為要幫子類去綁定和解綁那么就需要拿到子類的Presenter才行,但是又不能隨便一個類都能綁定的,因為只有基類的Presenter中才定義了綁定和解綁的方法,所以同樣的在類(基類Activity)上可以聲明泛型,在方法上使用泛型來達到目的**。
4. 修改Presenter和Activity中的代碼,各自繼承自己的基類并去除重復代碼
**實現步驟**:
1. 創建一個基類View,讓所有View接口都必須實現
~~~
/**
* @author 劉鎵旗
* @date 2017/11/17
* @description 所有mvpView的父接口
*/
public interface IMvpBaseView4 {
}
~~~
2. 創建一個基類的Presenter(AbstractMvpPersenter4),在**類上規定View泛型**,然后**定義綁定和解綁的方法**,**對外在提供一個獲取View的方法**(getmMvpView()),讓子類直接通過方法來獲取View使用即可
~~~
/**
* @author 劉鎵旗
* @date 2017/11/17
* @description 指定綁定的View必須繼承自IMvpBaseView4
*/
public abstract class AbstractMvpPersenter4<V extends IMvpBaseView4> {
private V mMvpView;
/**
* 綁定V層
* @param view
*/
public void attachMvpView(V view){
this.mMvpView = view;
}
/**
* 解除綁定V層
*/
public void detachMvpView(){
mMvpView = null;
}
/**
* 獲取V層
* @return
*/
public V getmMvpView() {
return mMvpView;
}
}
~~~
3. 創建一個基類的Activity,**聲明一個創建Presenter的抽象方法(abstract P createPresenter()),因為要幫子類去綁定和解綁那么就需要拿到子類的Presenter才行,但是又不能隨便一個類都能綁定的,因為只有基類的Presenter中才定義了綁定和解綁的方法,所以同樣的在類(基類Activity)上可以聲明泛型,在方法上使用泛型來達到目的**
~~~
/**
* @author 劉鎵旗
* @date 2017/11/17
* @description MvpActivity
* 指定子類具體的View必須繼承自IMvpBaseView4
* 指定子類具體的Presenter必須繼承自AbstractMvpPersenter4
*/
public abstract class AbstractMvpActivity<V extends IMvpBaseView4, P extends AbstractMvpPersenter4<V>> extends AppCompatActivity implements IMvpBaseView4 {
private P presenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//創建Presenter
if (presenter == null) {
presenter = createPresenter();
}
if (presenter == null) {
throw new NullPointerException("presenter 不能為空!");
}
//綁定view
presenter.attachMvpView((V) this);
}
@Override
protected void onDestroy() {
super.onDestroy();
//解除綁定
if (presenter != null) {
presenter.detachMvpView();
}
}
/**
* 創建Presenter
* @return 子類自己需要的Presenter
*/
protected abstract P createPresenter();
/**
* 獲取Presenter
* @return 返回子類創建的Presenter
*/
public P getPresenter() {
return presenter;
}
}
~~~
4. 修改Presenter和Activity中的代碼,各自繼承自己的基類并去除重復代碼
修改后的Presenter:
~~~
/**
* @author 劉鎵旗
* @date 2017/11/17
* @description P層
*/
public class RequestPresenter4 extends AbstractMvpPersenter4<RequestView4> {
private final RequestMode4 mRequestMode;
public RequestPresenter4() {
this.mRequestMode = new RequestMode4();
}
public void clickRequest(final String cityId){
//獲取View
if(getmMvpView() != null){
getmMvpView().requestLoading();
}
//模擬網絡延遲,可以顯示出加載中
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mRequestMode.request(cityId, new Callback<WeatherBean>() {
@Override
public void onResponse(Call<WeatherBean> call, Response<WeatherBean> response) {
//判斷View是否為空
if(getmMvpView() != null){
getmMvpView().resultSuccess(response.body());
}
}
@Override
public void onFailure(Call<WeatherBean> call, Throwable t) {
if(getmMvpView() != null){
getmMvpView().resultFailure(Log.getStackTraceString(t));
}
}
});
}
},1000);
}
public void interruptHttp(){
mRequestMode.interruptHttp();
}
}
~~~
修改后的Activity:
~~~
public class MainActivity extends AbstractMvpActivity<RequestView4, RequestPresenter4>
implements RequestView4 {
@FieldView(R.id.tv_text)
private TextView textView;
private RequestPresenter3 presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewFind.bind(this);
}
@Override
protected RequestPresenter4 createPresenter() {
return new RequestPresenter4();
}
//點擊事件
public void request(View view) {
getPresenter().clickRequest("101010100");
}
@Override
public void requestLoading() {
textView.setText("請求中,請稍后...");
}
@Override
public void resultSuccess(WeatherBean result) {
//成功
textView.setText(result.getWeatherinfo().toString());
}
@Override
public void resultFailure(String result) {
//失敗
textView.setText(result);
}
}
~~~
到這里完美了嗎?沒有,還可以再抽,來分析一下還有哪些不完美的地方以及如何再優化。
**五、高級抽象-使用注解、工廠模式、代理模式、策略模式整體解決代碼冗余、內存泄露、Presenter生命周期以及數據存儲問題**
1. **每個子類都要重寫父類創建Presenter的方法,創建一個Presenter并返回,這一步我們也可以讓父類幫忙干了**,怎么做呢?我們可以采用**注解的方式**,**在子類上聲明一個注解并注明要創建的類型,剩下的事情就讓父類去做了,但是父類得考慮如果子類不想這么干怎么辦,那也還是不能寫死吧,可以使用策略模式加工廠模式來實現**,我們**默認使用這種注解的工廠**,但是**如果子類不喜歡可以通過父類提供的一個方法來創建自己的工廠**。
2. **Presenter真正的創建過程,我們可以將它放到真正使用Presenter的時候再創建**,這樣的話可以稍微優化一下性能問題
3. **界面有可能會意外銷毀并重建**,Activity、Fragment、View都可以**在銷毀的時候通過onDestroy釋放一些資源并在onSaveInstanceState方法中存儲一些數據然后在重建的時候恢復,但是有可能Presenter中也需要釋放一些資源存儲一些數據,那么上面的結構就不能滿足了,我們可以給Presenter增加生命周期的方法,讓Presenter和V層生命周期同步就可以做到了**
4. 第三步中我們又給Presenter加入了一些生命周期的方法,再加上Presenter的創建綁定和解綁的方法,那么**如果我們在創建一個MvpFragment基類,或者View的基類那么這么多的代碼豈不是都要copy一份嗎,而且看起來也很不清晰,這里**我們可以**采用代理模式**來優化一下
好了下面來實現:
1. 我們既然要**采用工廠模式才創建Presenter**,那么我們首先來創建一個**工廠接口**
~~~
/**
* @author 劉鎵旗
* @date 2017/11/17
* @description Presenter工廠接口
*/
public interface PresenterMvpFactory<V extends BaseMvpView,P extends BaseMvpPresenter<V>> {
/**
* 創建Presenter的接口方法
* @return 需要創建的Presenter
*/
P createMvpPresenter();
}
~~~
2. 然后我們**需要創建一個默認使用注解創建的工廠**,那么首先要**創建一個注解**
**注解**:
~~~
/**
* @author 劉鎵旗
* @date 2017/11/17
* @description 標注創建Presenter的注解
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface CreatePresenter {
Class<? extends BaseMvpPresenter> value();
}
~~~
**注解工廠**:
~~~
/**
* @author 劉鎵旗
* @date 2017/11/17
* @description Presenter工廠實現類
*/
public class PresenterMvpFactoryImpl<V extends BaseMvpView, P extends BaseMvpPresenter<V>>
implements PresenterMvpFactory<V, P> {
/**
* 需要創建的Presenter的類型
*/
private final Class<P> mPresenterClass;
/**
* 根據注解創建Presenter的工廠實現類
* @param viewClazz 需要創建Presenter的V層實現類
* @param <V> 當前View實現的接口類型
* @param <P> 當前要創建的Presenter類型
* @return 工廠類
*/
public static <V extends BaseMvpView, P extends BaseMvpPresenter<V>> PresenterMvpFactoryImpl<V,P> createFactory(Class<?> viewClazz){
CreatePresenter annotation = viewClazz.getAnnotation(CreatePresenter.class);
Class<P> aClass = null;
if(annotation != null){
aClass = (Class<P>) annotation.value();
}
return aClass == null ? null : new PresenterMvpFactoryImpl<V, P>(aClass);
}
private PresenterMvpFactoryImpl(Class<P> presenterClass) {
this.mPresenterClass = presenterClass;
}
@Override
public P createMvpPresenter() {
try {
return mPresenterClass.newInstance();
} catch (Exception e) {
throw new RuntimeException("Presenter創建失敗!,檢查是否聲明了@CreatePresenter(xx.class)注解");
}
}
}
~~~
3. 我們說了**不能寫死這個工廠**,那么我們**需要使用者可以自定義**,那么我們還需要給使用者提供一個設置的方法,我們**定義一個接口提供設置工廠、獲取工廠、獲取Presenter的方法,然后讓V層來實現這個接口**,這樣V層的子類就可以通過相應的方法使用了
~~~
/**
* @author 劉鎵旗
* @date 2017/11/20
* @description 代理接口
*/
public interface PresenterProxyInterface<V extends BaseMvpView,P extends BaseMvpPresenter<V>> {
/**
* 設置創建Presenter的工廠
* @param presenterFactory PresenterFactory類型
*/
void setPresenterFactory(PresenterMvpFactory<V,P> presenterFactory);
/**
* 獲取Presenter的工廠類
* @return 返回PresenterMvpFactory類型
*/
PresenterMvpFactory<V,P> getPresenterFactory();
/**
* 獲取創建的Presenter
* @return 指定類型的Presenter
*/
P getMvpPresenter();
}
~~~
4. 給Presenter增加生命周期的方法
~~~
/**
* @author 劉鎵旗
* @date 2017/11/17
* @description 所有Presenter的基類,并不強制實現這些方法,有需要在重寫
*/
public class BaseMvpPresenter<V extends BaseMvpView> {
/**
* V層view
*/
private V mView;
/**
* Presenter被創建后調用
*
* @param savedState 被意外銷毀后重建后的Bundle
*/
public void onCreatePersenter(@Nullable Bundle savedState) {
Log.e("perfect-mvp","P onCreatePersenter = ");
}
/**
* 綁定View
*/
public void onAttachMvpView(V mvpView) {
mView = mvpView;
Log.e("perfect-mvp","P onResume");
}
/**
* 解除綁定View
*/
public void onDetachMvpView() {
mView = null;
Log.e("perfect-mvp","P onDetachMvpView = ");
}
/**
* Presenter被銷毀時調用
*/
public void onDestroyPersenter() {
Log.e("perfect-mvp","P onDestroy = ");
}
/**
* 在Presenter意外銷毀的時候被調用,它的調用時機和Activity、Fragment、View中的onSaveInstanceState
* 時機相同
*
* @param outState
*/
public void onSaveInstanceState(Bundle outState) {
Log.e("perfect-mvp","P onSaveInstanceState = ");
}
/**
* 獲取V層接口View
*
* @return 返回當前MvpView
*/
public V getMvpView() {
return mView;
}
}
~~~
5. 創建一個代理來管理Presenter的生命周期方法
~~~
/**
* @author 劉鎵旗
* @date 2017/11/20
* @description 代理實現類,用來管理Presenter的生命周期,還有和view之間的關聯
*/
public class BaseMvpProxy<V extends BaseMvpView, P extends BaseMvpPresenter<V>> implements PresenterProxyInterface<V, P>{
/**
* 獲取onSaveInstanceState中bundle的key
*/
private static final String PRESENTER_KEY = "presenter_key";
/**
* Presenter工廠類
*/
private PresenterMvpFactory<V, P> mFactory;
private P mPresenter;
private Bundle mBundle;
private boolean mIsAttchView;
public BaseMvpProxy(PresenterMvpFactory<V, P> presenterMvpFactory) {
this.mFactory = presenterMvpFactory;
}
/**
* 設置Presenter的工廠類,這個方法只能在創建Presenter之前調用,也就是調用getMvpPresenter()之前,如果Presenter已經創建則不能再修改
*
* @param presenterFactory PresenterFactory類型
*/
@Override
public void setPresenterFactory(PresenterMvpFactory<V, P> presenterFactory) {
if (mPresenter != null) {
throw new IllegalArgumentException("這個方法只能在getMvpPresenter()之前調用,如果Presenter已經創建則不能再修改");
}
this.mFactory = presenterFactory;
}
/**
* 獲取Presenter的工廠類
*
* @return PresenterMvpFactory類型
*/
@Override
public PresenterMvpFactory<V, P> getPresenterFactory() {
return mFactory;
}
/**
* 獲取創建的Presenter
*
* @return 指定類型的Presenter
* 如果之前創建過,而且是以外銷毀則從Bundle中恢復
*/
@Override
public P getMvpPresenter() {
Log.e("perfect-mvp","Proxy getMvpPresenter");
if (mFactory != null) {
if (mPresenter == null) {
mPresenter = mFactory.createMvpPresenter();
mPresenter.onCreatePersenter(mBundle == null ? null : mBundle.getBundle(PRESENTER_KEY));
}
}
Log.e("perfect-mvp","Proxy getMvpPresenter = " + mPresenter);
return mPresenter;
}
/**
* 綁定Presenter和view
* @param mvpView
*/
public void onResume(V mvpView) {
getMvpPresenter();
Log.e("perfect-mvp","Proxy onResume");
if (mPresenter != null && !mIsAttchView) {
mPresenter.onAttachMvpView(mvpView);
mIsAttchView = true;
}
}
/**
* 銷毀Presenter持有的View
*/
private void onDetachMvpView() {
Log.e("perfect-mvp","Proxy onDetachMvpView = ");
if (mPresenter != null && mIsAttchView) {
mPresenter.onDetachMvpView();
mIsAttchView = false;
}
}
/**
* 銷毀Presenter
*/
public void onDestroy() {
Log.e("perfect-mvp","Proxy onDestroy = ");
if (mPresenter != null ) {
onDetachMvpView();
mPresenter.onDestroyPersenter();
mPresenter = null;
}
}
/**
* 意外銷毀的時候調用
* @return Bundle,存入回調給Presenter的Bundle和當前Presenter的id
*/
public Bundle onSaveInstanceState() {
Log.e("perfect-mvp","Proxy onSaveInstanceState = ");
Bundle bundle = new Bundle();
getMvpPresenter();
if(mPresenter != null){
Bundle presenterBundle = new Bundle();
//回調Presenter
mPresenter.onSaveInstanceState(presenterBundle);
bundle.putBundle(PRESENTER_KEY,presenterBundle);
}
return bundle;
}
/**
* 意外關閉恢復Presenter
* @param savedInstanceState 意外關閉時存儲的Bundler
*/
public void onRestoreInstanceState(Bundle savedInstanceState) {
Log.e("perfect-mvp","Proxy onRestoreInstanceState = ");
Log.e("perfect-mvp","Proxy onRestoreInstanceState Presenter = " + mPresenter);
mBundle = savedInstanceState;
}
}
~~~
6. 最后**V層實現**,首先**實現設置工廠的接口**,然**后創建一個代理并傳入默認工廠**,**在V層生命周期中使用代理去實現管理Presenter的生命周期 **
~~~
/**
* @author 劉鎵旗
* @date 2017/11/17
* @description 繼承自Activity的基類MvpActivity
* 使用代理模式來代理Presenter的創建、銷毀、綁定、解綁以及Presenter的狀態保存,其實就是管理Presenter的生命周期
*/
public abstract class AbstractMvpActivitiy<V extends BaseMvpView, P extends BaseMvpPresenter<V>> extends Activity implements PresenterProxyInterface<V,P> {
private static final String PRESENTER_SAVE_KEY = "presenter_save_key";
/**
* 創建被代理對象,傳入默認Presenter的工廠
*/
private BaseMvpProxy<V,P> mProxy = new BaseMvpProxy<>(PresenterMvpFactoryImpl.<V,P>createFactory(getClass()));
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e("perfect-mvp","V onCreate");
Log.e("perfect-mvp","V onCreate mProxy = " + mProxy);
Log.e("perfect-mvp","V onCreate this = " + this.hashCode());
if(savedInstanceState != null){
mProxy.onRestoreInstanceState(savedInstanceState.getBundle(PRESENTER_SAVE_KEY));
}
}
@Override
protected void onResume() {
super.onResume();
Log.e("perfect-mvp","V onResume");
mProxy.onResume((V) this);
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.e("perfect-mvp","V onDestroy = " );
mProxy.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.e("perfect-mvp","V onSaveInstanceState");
outState.putBundle(PRESENTER_SAVE_KEY,mProxy.onSaveInstanceState());
}
@Override
public void setPresenterFactory(PresenterMvpFactory<V, P> presenterFactory) {
Log.e("perfect-mvp","V setPresenterFactory");
mProxy.setPresenterFactory(presenterFactory);
}
@Override
public PresenterMvpFactory<V, P> getPresenterFactory() {
Log.e("perfect-mvp","V getPresenterFactory");
return mProxy.getPresenterFactory();
}
@Override
public P getMvpPresenter() {
Log.e("perfect-mvp","V getMvpPresenter");
return mProxy.getMvpPresenter();
}
}
~~~
最后看一下使用,首先在V層上定義**需要創建的Presenter**,**聲明自己模塊具體的View接口類型和Presenter類型**,**最后實現自己View接口就ok了**,還有就是**如果要設置自己的Presenter創建工廠,必須在調用onResume方法和getMvpPresenter方法之前設置 **
~~~
//聲明需要創建的Presenter
@CreatePresenter(RequestPresenter5.class)
public class MainActivity extends AbstractMvpAppCompatActivity<RequestView5, RequestPresenter5> implements RequestView5 {
@FieldView(R.id.tv_text)
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewFind.bind(this);
//設置自己的Presenter工廠,如果你想自定義的話
// setPresenterFactory(xxx);
if(savedInstanceState != null){
Log.e("perfect-mvp","MainActivity onCreate 測試 = " + savedInstanceState.getString("test") );
}
}
//點擊事件
public void request(View view) {
Log.e("perfect-mvp","點擊事件");
getMvpPresenter().clickRequest("101010100");
}
@Override
public void requestLoading() {
textView.setText("請求中,請稍后...");
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.e("perfect-mvp","MainActivity onSaveInstanceState 測試");
outState.putString("test","test_save");
}
@Override
public void resultSuccess(WeatherBean result) {
//成功
textView.setText(result.getWeatherinfo().toString());
}
@Override
public void resultFailure(String result) {
//失敗
textView.setText(result);
}
}
~~~
這時候**如果界面意外銷毀**,**Presenter可以通過重寫以下方法進行釋放資源,存儲數據,和恢復數據**,例如:
~~~
@Override
public void onCreatePersenter(@Nullable Bundle savedState) {
super.onCreatePersenter(savedState);
if(savedState != null){
Log.e("perfect-mvp","RequestPresenter5 onCreatePersenter 測試 = " + savedState.getString("test2") );
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.e("perfect-mvp","RequestPresenter5 onSaveInstanceState 測試 " );
outState.putString("test2","test_save2");
}
@Override
public void onDestroyPersenter() {
super.onDestroyPersenter();
}
~~~
哦了!大功告成,perfect!可能有的人會說這只是Activity,那么Fragment中怎么弄呢,其實是一模一樣的,我們將實現全部抽離到了 代理中,那么Fragment中也只需要創建一個代理,然后在生命周期中使用代理調用相應就好了,當然最后我的庫中已經實現了Fragment的基類和AppCompatActivity的基類,至于View的如果有使用到的可以自行擴展,再次聲明本文只是提供一種思路和封裝的方法,并不代表就是最好的,如果有更好的想法和思路可以一起探討。
最后奉上github地址,還希望可以給個star鼓勵一下。再次感謝!
GitHub封裝庫地址:[perfect-mvp ](https://github.com/ljqloveyou123/perfect-mvp)