MVP 全稱:Model-View-Presenter 孝偎;MVP 是從經(jīng)典的模式MVC演變而來惠昔,它們的基本思想有相通的地方
Controller/Presenter負(fù)責(zé)邏輯的處理,Model提供數(shù)據(jù),View負(fù)責(zé)顯示。
作為一種新的模式,MVP與MVC有著一個(gè)重大的區(qū)別:在MVP中View并不直接使用Model鱼响,它們之間的通信是通過Presenter (MVC中的Controller)來進(jìn)行的,所有的交互都發(fā)生在Presenter內(nèi)部组底,而在MVC中View會直接從Model中讀取數(shù)據(jù)而不是通過 Controller丈积。
優(yōu)點(diǎn):
- 模型與視圖完全分離筐骇,我們可以修改視圖而不影響模型
- 可以更高效地使用模型,因?yàn)樗械慕换ザ及l(fā)生在一個(gè)地方——Presenter內(nèi)部
- 我們可以將一個(gè)Presenter用于多個(gè)視圖江滨,而不需要改變Presenter的邏輯铛纬。這個(gè)特性非常的有用,因?yàn)橐晥D的變化總是比模型的變化頻繁唬滑。
- 如果我們把邏輯放在Presenter中告唆,那么我們就可以脫離用戶接口來測試這些邏輯(單元測試)
在MVC里,View是可以直接訪問Model的晶密!從而擒悬,View里會包含Model信息,不可避免的還要包括一些業(yè)務(wù)邏輯稻艰。 在MVC模型里懂牧,更關(guān)注的Model的不變,而同時(shí)有多個(gè)對Model的不同顯示尊勿,即View僧凤。所以,在MVC模型里运怖,Model不依賴于View拼弃,但是View是依賴于Model的夏伊。不僅如此摇展,因?yàn)橛幸恍I(yè)務(wù)邏輯在View里實(shí)現(xiàn)了,導(dǎo)致要更改View也是比較困難的溺忧,至少那些業(yè)務(wù)邏輯是無法重用的咏连。
雖然 MVC 中的 View 的確“可以”訪問 Model,但是我們不建議在 View 中依賴 Model鲁森,而是要求盡可能把所有業(yè)務(wù)邏輯都放在 Controller 中處理祟滴,而 View 只和 Controller 交互。
本文不講解什么是MVP歌溉,如果還不太了解MVP請自行查閱資料垄懂,并看我另外一個(gè)項(xiàng)目
本文重點(diǎn)是封裝一個(gè)高級MVP架構(gòu),會詳細(xì)的講解如何一步步從無到有的封裝成一個(gè)高級MVP架構(gòu)過程痛垛。
眾所周知普通的MVP模式存在內(nèi)存泄露草慧、代碼冗余、界面意外關(guān)閉后在重建數(shù)據(jù)緩存等問題匙头,本文最終封裝的成果為一一解決這些問題漫谷,而且在使用過程中盡量做到使用簡單而且可擴(kuò)展,當(dāng)然本文也只是提供了一種封裝思路而已,如果不能滿足你的需求還可以自行再進(jìn)行擴(kuò)展蹂析。
如果你覺得你不想看整個(gè)實(shí)現(xiàn)思路可以直接看最后的源碼舔示,望給點(diǎn)個(gè)star鼓勵一下
文章會以5個(gè)部分來整體優(yōu)化封裝MVP碟婆,也是一個(gè)從無到有的過程
一、不使用MVP的代碼
二惕稻、最簡單的MVP實(shí)現(xiàn)
三竖共、解決MVP內(nèi)存泄露
四、簡單抽象-解決MVP代碼冗余
五俺祠、高級抽象-使用注解肘迎、工廠模式、代理模式锻煌、策略模式整體解決代碼冗余妓布、內(nèi)存泄露、Presenter生命周期以及數(shù)據(jù)存儲問題
進(jìn)入正題宋梧。
場景:假如界面有一個(gè)按鈕匣沼,點(diǎn)擊后請求數(shù)據(jù),然后成功后將返回的數(shù)據(jù)設(shè)置到一個(gè)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);
}
//按鈕點(diǎn)擊事件
public void request(View view) {
clickRequest("101010100");
}
//發(fā)起請求
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模式來改造這個(gè)代碼。
二倦沧、最簡單的MVP實(shí)現(xiàn)
思路如下:
1唇撬、首先我們先定義一個(gè)接口,用來規(guī)定針對這個(gè)界面邏輯View需要作出的動作的接口展融。
2窖认、讓Activity實(shí)現(xiàn)這個(gè)接口中的方法,也就是V層
3告希、創(chuàng)建一個(gè)類扑浸,用來封裝之前的網(wǎng)絡(luò)請求過程,也就是M層
4燕偶、再創(chuàng)建一個(gè)類喝噪,用來處理M層和V層之間的通信,也就是P層
下面來實(shí)現(xiàn)一下:
1指么、首先我們先定義一個(gè)接口酝惧,用來規(guī)定針對這個(gè)界面邏輯View需要作出的動作的接口。
/**
* @author zhuxh
* @date 2017/11/16
* @description V層接口伯诬,定義V層需要作出的動作的接口
*/
public interface RequestView1 {
//請求時(shí)展示加載
void requestLoading();
//請求成功
void resultSuccess(WeatherBean result);
//請求失敗
void resultFailure(String result);
}
2晚唇、讓Activity實(shí)現(xiàn)這個(gè)接口中的方法,也就是V層
/**
* 第二步:對應(yīng)demo1
* 2缺亮,最簡單的mvp模式,
* 1.Activity需要實(shí)現(xiàn)v層接口
* 2.Persenter需要持有v層引用和m層引用
* 3.在實(shí)現(xiàn)類view中創(chuàng)建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);
//創(chuàng)建Presenter
presenter = new RequestPresenter1(this);
}
//點(diǎn)擊事件
public void request(View view) {
presenter.clickRequest("101010100");
}
//請求時(shí)加載
@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、創(chuàng)建一個(gè)類,用來封裝之前的網(wǎng)絡(luò)請求過程萌踱,也就是M層
/**
* @author zhuxh
* @date 2017/11/16
* @description M層 數(shù)據(jù)層
*/
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葵礼、再創(chuàng)建一個(gè)類,用來處理M層和V層之間的通信并鸵,也就是P層
/**
* @author zhuxh
* @date 2017/11/16
* @description P層
* 特點(diǎn):需要持有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){
//請求時(shí)顯示加載
mRequestView.requestLoading();
//模擬耗時(shí)鸳粉,可以展示出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模式的使用了园担,可是這樣寫會內(nèi)存泄露届谈,因?yàn)槿绻诰W(wǎng)絡(luò)請求的過程中Activity就關(guān)閉了,Presenter還持有了V層的引用弯汰,也就是MainActivity艰山,就會內(nèi)存泄露。
三咏闪、解決MVP內(nèi)存泄露
下面就來解決這個(gè)問題曙搬,我們將P層和V層的關(guān)聯(lián)抽出兩個(gè)方法,一個(gè)綁定鸽嫂,一個(gè)解綁纵装,在需要的時(shí)候進(jìn)行綁定V層,不需要的時(shí)候進(jìn)行解綁就可以了据某。我們只需要修改上面Presenter中的構(gòu)造代碼橡娄,不需要在構(gòu)造中傳遞V層了,然后再寫一個(gè)綁定和解綁的方法癣籽,最后修改Activity創(chuàng)建Presenter時(shí)進(jìn)行綁定挽唉,在onDestroy中進(jìn)行解綁。
修改后的Presenter:
/**
* @author zhuxh
* @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;
}
/**
* 取消網(wǎng)絡(luò)請求
*/
public void interruptHttp(){
mMode.interruptHttp();
}
}
修改后的MainActivity:
/**
* 第三步:對應(yīng)demo2
* 上面的問題:
* 1.是會內(nèi)存泄露才避,因?yàn)閜ersenter一直持有Activity橱夭,如果一個(gè)發(fā)了一個(gè)請求,但是網(wǎng)絡(luò)有點(diǎn)慢桑逝,這個(gè)時(shí)候退出Activity,那么請求回來后還是會調(diào)用
* Activity的回調(diào)方法俏让,這里還是因?yàn)橐恢背钟械膯栴}
* 2.如果已經(jīng)退出了當(dāng)前界面楞遏,這個(gè)請求也沒有用了,這個(gè)時(shí)候我們可以斷開請求
* <p>
* 解決問題:
* 1.增加綁定和解綁的方法來解決內(nèi)存泄露和退出后還會回調(diào)的問題
* 2首昔、增加斷開網(wǎng)絡(luò)連接的方法
*/
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();
}
}
這樣我們就解決了內(nèi)存泄露的問題寡喝,但是這樣還是不完美,應(yīng)用中肯定不可能只有一個(gè)模塊勒奇,每個(gè)模塊都對應(yīng)著一個(gè)V層和P層预鬓,那這樣的話每個(gè)Presenter中都要定義綁定和解綁的方法,而Activity中對應(yīng)的也要調(diào)用這綁定和解綁的兩個(gè)方法赊颠,代碼冗余格二。
四劈彪、簡單抽象-解決MVP代碼冗余
針對這個(gè)問題我們可以抽取出一個(gè)基類的Presenter和一個(gè)基類的Activity來做這個(gè)事情,讓子類不用在寫這些重復(fù)的代碼顶猜。但是問題又來了沧奴,既然是基類,肯定不止有一個(gè)子類來繼承基類长窄,那么也就是說子類當(dāng)中定義的View接口和需要創(chuàng)建的Presenter都不相同滔吠,我們肯定在基類當(dāng)中不能寫死吧,那就使用泛型來設(shè)計(jì)挠日。
思路:
1.創(chuàng)建一個(gè)基類View疮绷,讓所有View接口都必須實(shí)現(xiàn),這個(gè)View可以什么都不做只是用來約束類型的
2.創(chuàng)建一個(gè)基類的Presenter,在類上規(guī)定View泛型嚣潜,然后定義綁定和解綁的抽象方法矗愧,讓子類去實(shí)現(xiàn),對外在提供一個(gè)獲取View的方法郑原,
讓子類直接通過方法來獲取View
3.創(chuàng)建一個(gè)基類的Activity唉韭,聲明一個(gè)創(chuàng)建Presenter的抽象方法,因?yàn)橐獛妥宇惾ソ壎ê徒饨壞敲淳托枰玫阶宇惖腜resenter才行犯犁,但是又不能隨便一個(gè)類都能綁定的属愤,因?yàn)橹挥谢惖腜resenter中才定義了綁定和解綁的方法,所以同樣的在類上可以聲明泛型在酸役,方法上使用泛型來達(dá)到目的住诸。
4.修改Presenter和Activity中的代碼,各自繼承自己的基類并去除重復(fù)代碼
實(shí)現(xiàn)步驟:
1.創(chuàng)建一個(gè)基類View涣澡,讓所有View接口都必須實(shí)現(xiàn)
/**
* @author zhuxh
* @date 2017/11/17
* @description 所有mvpView的父接口
*/
public interface IMvpBaseView4 {
}
2.創(chuàng)建一個(gè)基類的Presenter贱呐,在類上規(guī)定View泛型,然后定義綁定和解綁的方法入桂,對外在提供一個(gè)獲取View的方法奄薇,讓子類直接通過方法來獲取View使用即可
/**
* @author zhuxh
* @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.創(chuàng)建一個(gè)基類的Activity,聲明一個(gè)創(chuàng)建Presenter的抽象方法抗愁,因?yàn)橐獛妥宇惾ソ壎ê徒饨壞敲淳托枰玫阶宇惖腜resenter才行馁蒂,但是又不能隨便一個(gè)類都能綁定的镜廉,因?yàn)橹挥谢惖腜resenter中才定義了綁定和解綁的方法吧凉,所以同樣的在類上可以聲明泛型在方法上使用泛型來達(dá)到目的
/**
* @author zhuxh
* @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);
//創(chuàng)建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();
}
}
/**
* 創(chuàng)建Presenter
* @return 子類自己需要的Presenter
*/
protected abstract P createPresenter();
/**
* 獲取Presenter
* @return 返回子類創(chuàng)建的Presenter
*/
public P getPresenter() {
return presenter;
}
}
4.修改Presenter和Activity中的代碼,各自繼承自己的基類并去除重復(fù)代碼
修改后的Presenter:
/**
* @author zhuxh
* @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();
}
//模擬網(wǎng)絡(luò)延遲俱饿,可以顯示出加載中
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();
}
//點(diǎn)擊事件
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);
}
}
到這里完美了嗎撮珠?沒有沮脖,還可以再抽,來分析一下還有哪些不完美的地方以及如何再優(yōu)化。
五勺届、高級抽象-使用注解驶俊、工廠模式、代理模式涮因、策略模式整體解決代碼冗余废睦、內(nèi)存泄露、Presenter生命周期以及數(shù)據(jù)存儲問題
1.每個(gè)子類都要重寫父類創(chuàng)建Presenter的方法养泡,創(chuàng)建一個(gè)Presenter并返回嗜湃,這一步我們也可以讓父類幫忙干了,怎么做呢澜掩?我們可以采用注解的方式购披,在子類上聲明一個(gè)注解并注明要創(chuàng)建的類型,剩下的事情就讓父類去做了,但是父類得考慮如果子類不想這么干怎么辦肩榕,那也還是不能寫死吧刚陡,可以使用策略模式加工廠模式來實(shí)現(xiàn),我們默認(rèn)使用這種注解的工廠
株汉,但是如果子類不喜歡可以通過父類提供的一個(gè)方法來創(chuàng)建自己的工廠筐乳。
2.Presenter真正的創(chuàng)建過程,我們可以將它放到真正使用Presenter的時(shí)候再創(chuàng)建乔妈,這樣的話可以稍微優(yōu)化一下性能問題
3.界面有可能會意外銷毀并重建蝙云,Activity、Fragment路召、View都可以在銷毀的時(shí)候通過onDestroy釋放一些資源并在onSaveInstanceState方法中存儲一些數(shù)據(jù)然后在重建的時(shí)候恢復(fù)勃刨,但是有可能Presenter中也需要釋放一些資源存儲一些數(shù)據(jù),那么上面的結(jié)構(gòu)就不能滿足了股淡,我們可以給Presenter增加生命周期的方法身隐,讓Presenter和V層生命周期同步就可以做到了
4.第三步中我們又給Presenter加入了一些生命周期的方法,再加上Presenter的創(chuàng)建綁定和解綁的方法唯灵,那么如果我們在創(chuàng)建一個(gè)MvpFragment基類贾铝,或者View的基類那么這么多的代碼豈不是都要copy一份嗎,而且看起來也很不清晰早敬,這里我們可以采用代理模式來優(yōu)化一下
好了下面來實(shí)現(xiàn):
1.我們既然要采用工廠模式才創(chuàng)建Presenter忌傻,那么我們首先來創(chuàng)建一個(gè)工廠接口
/**
* @author zhuxh
* @date 2017/11/17
* @description Presenter工廠接口
*/
public interface PresenterMvpFactory<V extends BaseMvpView,P extends BaseMvpPresenter<V>> {
/**
* 創(chuàng)建Presenter的接口方法
* @return 需要創(chuàng)建的Presenter
*/
P createMvpPresenter();
}
2.然后我們需要創(chuàng)建一個(gè)默認(rèn)使用注解創(chuàng)建的工廠,那么首先要創(chuàng)建一個(gè)注解
注解:
/**
* @author zhuxh
* @date 2017/11/17
* @description 標(biāo)注創(chuàng)建Presenter的注解
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface CreatePresenter {
Class<? extends BaseMvpPresenter> value();
}
注解工廠:
/**
* @author zhuxh
* @date 2017/11/17
* @description Presenter工廠實(shí)現(xiàn)類
*/
public class PresenterMvpFactoryImpl<V extends BaseMvpView, P extends BaseMvpPresenter<V>> implements PresenterMvpFactory<V, P> {
/**
* 需要創(chuàng)建的Presenter的類型
*/
private final Class<P> mPresenterClass;
/**
* 根據(jù)注解創(chuàng)建Presenter的工廠實(shí)現(xiàn)類
* @param viewClazz 需要創(chuàng)建Presenter的V層實(shí)現(xiàn)類
* @param <V> 當(dāng)前View實(shí)現(xiàn)的接口類型
* @param <P> 當(dāng)前要創(chuàng)建的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創(chuàng)建失敗!搞监,檢查是否聲明了@CreatePresenter(xx.class)注解");
}
}
}
3.我們說了不能寫死這個(gè)工廠,那么我們需要使用者可以自定義镰矿,那么我們還需要給使用者提供一個(gè)設(shè)置的方法琐驴,我們定義一個(gè)接口提供設(shè)置工廠、獲取工廠、獲取Presenter的方法绝淡,然后讓V層來實(shí)現(xiàn)這個(gè)接口宙刘,這樣V層的子類就可以通過相應(yīng)的方法使用了
/**
* @author zhuxh
* @date 2017/11/20
* @description 代理接口
*/
public interface PresenterProxyInterface<V extends BaseMvpView,P extends BaseMvpPresenter<V>> {
/**
* 設(shè)置創(chuàng)建Presenter的工廠
* @param presenterFactory PresenterFactory類型
*/
void setPresenterFactory(PresenterMvpFactory<V,P> presenterFactory);
/**
* 獲取Presenter的工廠類
* @return 返回PresenterMvpFactory類型
*/
PresenterMvpFactory<V,P> getPresenterFactory();
/**
* 獲取創(chuàng)建的Presenter
* @return 指定類型的Presenter
*/
P getMvpPresenter();
}
4.給Presenter增加生命周期的方法
/**
* @author zhuxh
* @date 2017/11/17
* @description 所有Presenter的基類,并不強(qiáng)制實(shí)現(xiàn)這些方法牢酵,有需要在重寫
*/
public class BaseMvpPresenter<V extends BaseMvpView> {
/**
* V層view
*/
private V mView;
/**
* Presenter被創(chuàng)建后調(diào)用
*
* @param savedState 被意外銷毀后重建后的Bundle
*/
public void onCreatePresenter(@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被銷毀時(shí)調(diào)用
*/
public void onDestroyPresenter() {
Log.e("perfect-mvp","P onDestroy = ");
}
/**
* 在Presenter意外銷毀的時(shí)候被調(diào)用悬包,它的調(diào)用時(shí)機(jī)和Activity、Fragment馍乙、View中的onSaveInstanceState
* 時(shí)機(jī)相同
*
* @param outState
*/
public void onSaveInstanceState(Bundle outState) {
Log.e("perfect-mvp","P onSaveInstanceState = ");
}
/**
* 獲取V層接口View
*
* @return 返回當(dāng)前MvpView
*/
public V getMvpView() {
return mView;
}
}
5.創(chuàng)建一個(gè)代理來管理Presenter的生命周期方法
/**
* @author zhuxh
* @date 2017/11/20
* @description 代理實(shí)現(xiàn)類布近,用來管理Presenter的生命周期,還有和view之間的關(guān)聯(lián)
*/
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;
}
/**
* 設(shè)置Presenter的工廠類,這個(gè)方法只能在創(chuàng)建Presenter之前調(diào)用,也就是調(diào)用getMvpPresenter()之前丝格,如果Presenter已經(jīng)創(chuàng)建則不能再修改
*
* @param presenterFactory PresenterFactory類型
*/
@Override
public void setPresenterFactory(PresenterMvpFactory<V, P> presenterFactory) {
if (mPresenter != null) {
throw new IllegalArgumentException("這個(gè)方法只能在getMvpPresenter()之前調(diào)用撑瞧,如果Presenter已經(jīng)創(chuàng)建則不能再修改");
}
this.mFactory = presenterFactory;
}
/**
* 獲取Presenter的工廠類
*
* @return PresenterMvpFactory類型
*/
@Override
public PresenterMvpFactory<V, P> getPresenterFactory() {
return mFactory;
}
/**
* 獲取創(chuàng)建的Presenter
*
* @return 指定類型的Presenter
* 如果之前創(chuàng)建過,而且是以外銷毀則從Bundle中恢復(fù)
*/
@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;
}
}
/**
* 意外銷毀的時(shí)候調(diào)用
* @return Bundle显蝌,存入回調(diào)給Presenter的Bundle和當(dāng)前Presenter的id
*/
public Bundle onSaveInstanceState() {
Log.e("perfect-mvp","Proxy onSaveInstanceState = ");
Bundle bundle = new Bundle();
getMvpPresenter();
if(mPresenter != null){
Bundle presenterBundle = new Bundle();
//回調(diào)Presenter
mPresenter.onSaveInstanceState(presenterBundle);
bundle.putBundle(PRESENTER_KEY,presenterBundle);
}
return bundle;
}
/**
* 意外關(guān)閉恢復(fù)Presenter
* @param savedInstanceState 意外關(guān)閉時(shí)存儲的Bundler
*/
public void onRestoreInstanceState(Bundle savedInstanceState) {
Log.e("perfect-mvp","Proxy onRestoreInstanceState = ");
Log.e("perfect-mvp","Proxy onRestoreInstanceState Presenter = " + mPresenter);
mBundle = savedInstanceState;
}
}
6.最后V層實(shí)現(xiàn)预伺,首先實(shí)現(xiàn)設(shè)置工廠的接口,然后創(chuàng)建一個(gè)代理并傳入默認(rèn)工廠曼尊,在V層生命周期中使用代理去實(shí)現(xiàn)管理Presenter的生命周期
/**
* @author zhuxh
* @date 2017/11/17
* @description 繼承自Activity的基類MvpActivity
* 使用代理模式來代理Presenter的創(chuàng)建酬诀、銷毀、綁定骆撇、解綁以及Presenter的狀態(tài)保存,其實(shí)就是管理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";
/**
* 創(chuàng)建被代理對象,傳入默認(rèn)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層上定義需要創(chuàng)建的Presenter,聲明自己模塊具體的View接口類型和Presenter類型艾船,最后實(shí)現(xiàn)自己View接口就ok了葵腹,還有就是如果要設(shè)置自己的Presenter創(chuàng)建工廠,必須在調(diào)用onResume方法和getMvpPresenter方法之前設(shè)置
//聲明需要創(chuàng)建的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);
//設(shè)置自己的Presenter工廠屿岂,如果你想自定義的話
// setPresenterFactory(xxx);
if(savedInstanceState != null){
Log.e("perfect-mvp","MainActivity onCreate 測試 = " + savedInstanceState.getString("test") );
}
}
//點(diǎn)擊事件
public void request(View view) {
Log.e("perfect-mvp","點(diǎn)擊事件");
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);
}
}
這時(shí)候如果界面意外銷毀,Presenter可以通過重寫以下方法進(jìn)行釋放資源践宴,存儲數(shù)據(jù),和恢復(fù)數(shù)據(jù)爷怀,例如:
@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中怎么弄呢,其實(shí)是一模一樣的吁朦,我們將實(shí)現(xiàn)全部抽離到了
代理中柒室,那么Fragment中也只需要創(chuàng)建一個(gè)代理,然后在生命周期中使用代理調(diào)用相應(yīng)就好了逗宜,當(dāng)然最后我的庫中已經(jīng)實(shí)現(xiàn)了Fragment的基類和AppCompatActivity的基類雄右,至于View的如果有使用到的可以自行擴(kuò)展空骚,再次聲明本文只是提供一種思路和封裝的方法,并不代表就是最好的擂仍,如果有更好的想法和思路可以一起探討囤屹。
最后奉上github地址