高級(jí)MVP架構(gòu)封裝演變?nèi)^(guò)程

概述

本文重點(diǎn)是封裝一個(gè)高級(jí)MVP架構(gòu),會(huì)詳細(xì)的講解如何一步步從無(wú)到有的封裝成一個(gè)高級(jí)MVP架構(gòu)過(guò)程首昔。

出差廈門(mén)譽(yù)游網(wǎng)絡(luò)時(shí)工位

文章會(huì)以5個(gè)部分來(lái)整體優(yōu)化封裝MVP织阅,也是一個(gè)從無(wú)到有的過(guò)程

一便瑟、不使用MVP的代碼

二坟募、最簡(jiǎn)單的MVP實(shí)現(xiàn)

三岛蚤、解決MVP內(nèi)存泄露

四、簡(jiǎn)單抽象-解決MVP代碼冗余

五懈糯、高級(jí)抽象-使用注解涤妒、工廠模式、代理模式赚哗、策略模式整體解決代碼冗余她紫、內(nèi)存泄露、Presenter生命周期以及數(shù)據(jù)存儲(chǔ)問(wèn)題

不廢話了屿储,進(jìn)入正題贿讹。

場(chǎng)景:假如界面有一個(gè)按鈕,點(diǎn)擊后請(qǐng)求數(shù)據(jù)够掠,然后成功后將返回的數(shù)據(jù)設(shè)置到一個(gè)Textview中

不使用MVP的代碼

一民褂、不使用MVP的代碼,一般我們會(huì)這么寫(xiě)

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ā)起請(qǐng)求
    public void clickRequest(final String cityId) {
        //請(qǐng)求接口
        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);
        //請(qǐng)求
        Call<WeatherBean> weatherBeanCall = apiService.requestWeather(cityId);
        weatherBeanCall.enqueue(new Callback<WeatherBean>() {
            @Override
            public void onResponse(Call<WeatherBean> call, Response<WeatherBean> response) {
                //請(qǐng)求成功
                textView.setText(response.body().getWeatherinfo().toString());
            }
            @Override
            public void onFailure(Call<WeatherBean> call, Throwable t) {
                //請(qǐng)求失敗
            }
        });
    }
}

上面的代碼是最原始的寫(xiě)法,下面我們使用最簡(jiǎn)單的MVP模式來(lái)改造這個(gè)代碼疯潭。

最簡(jiǎn)單的MVP實(shí)現(xiàn)

思路如下:

1赊堪、首先我們先定義一個(gè)接口,用來(lái)規(guī)定針對(duì)這個(gè)界面邏輯View需要作出的動(dòng)作的接口竖哩。
2哭廉、讓Activity實(shí)現(xiàn)這個(gè)接口中的方法,也就是V層
3期丰、創(chuàng)建一個(gè)類(lèi)群叶,用來(lái)封裝之前的網(wǎng)絡(luò)請(qǐng)求過(guò)程,也就是M層
4钝荡、再創(chuàng)建一個(gè)類(lèi),用來(lái)處理M層和V層之間的通信舶衬,也就是P層

下面來(lái)實(shí)現(xiàn)一下:

1埠通、首先我們先定義一個(gè)接口,用來(lái)規(guī)定針對(duì)這個(gè)界面邏輯View需要作出的動(dòng)作的接口逛犹。
/**
 * @author
 * @date 2017/11/16
 * @description V層接口端辱,定義V層需要作出的動(dòng)作的接口
 */
public interface RequestView1 {
    //請(qǐng)求時(shí)展示加載
    void requestLoading();
    //請(qǐng)求成功
    void resultSuccess(WeatherBean result);
    //請(qǐng)求失敗
    void resultFailure(String result);
}
2、讓Activity實(shí)現(xiàn)這個(gè)接口中的方法虽画,也就是V層
/**
 *   第二步:對(duì)應(yīng)demo1
 * 2舞蔽,最簡(jiǎn)單的mvp模式,
 * 1.Activity需要實(shí)現(xiàn)v層接口
 * 2.Persenter需要持有v層引用和m層引用
 * 3.在實(shí)現(xiàn)類(lèi)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");
    }
    //請(qǐng)求時(shí)加載
    @Override
    public void requestLoading() {
        textView.setText("請(qǐng)求中,請(qǐng)稍后...");
    }
    //請(qǐng)求成功
    @Override
    public void resultSuccess(WeatherBean result) {
        //成功
        textView.setText(result.getWeatherinfo().toString());
    }
    //請(qǐng)求失敗
    @Override
    public void resultFailure(String result) {
        //失敗
        textView.setText(result);
    }
}
3、創(chuàng)建一個(gè)類(lèi)码撰,用來(lái)封裝之前的網(wǎng)絡(luò)請(qǐng)求過(guò)程渗柿,也就是M層
/**
 * @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){
       //請(qǐng)求接口
       Retrofit retrofit  = new Retrofit.Builder()
               //代表root地址
               .baseUrl(BASE_URL)
               .addConverterFactory(ScalarsConverterFactory.create())
               .addConverterFactory(GsonConverterFactory.create())
               .build();
       ApiService apiService = retrofit.create(ApiService.class);
       //請(qǐng)求
       Call<WeatherBean> weatherBeanCall = apiService.requestWeather(detailId);
       weatherBeanCall.enqueue(callback);
   }
}
4、再創(chuàng)建一個(gè)類(lèi),用來(lái)處理M層和V層之間的通信朵栖,也就是P層
/**
 * @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){
        //請(qǐng)求時(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模式的使用了陨溅,可是這樣寫(xiě)會(huì)內(nèi)存泄露终惑,因?yàn)槿绻诰W(wǎng)絡(luò)請(qǐng)求的過(guò)程中Activity就關(guān)閉了,Presenter還持有了V層的引用门扇,也就是MainActivity雹有,就會(huì)內(nèi)存泄露。

解決MVP內(nèi)存泄露

下面就來(lái)解決這個(gè)問(wèn)題臼寄,我們將P層和V層的關(guān)聯(lián)抽出兩個(gè)方法霸奕,一個(gè)綁定,一個(gè)解綁脯厨,在需要的時(shí)候進(jìn)行綁定V層铅祸,不需要的時(shí)候進(jìn)行解綁就可以了。

我們只需要修改上面Presenter中的構(gòu)造代碼合武,不需要在構(gòu)造中傳遞V層了临梗,然后再寫(xiě)一個(gè)綁定和解綁的方法,最后修改Activity創(chuàng)建Presenter時(shí)進(jìn)行綁定稼跳,在onDestroy中進(jìn)行解綁盟庞。

修改后的Presenter:

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ò)請(qǐng)求
     */
    public void interruptHttp(){
        mMode.interruptHttp();
    }
}

修改后的MainActivity:

/**
 * 第三步:對(duì)應(yīng)demo2
 * 上面的問(wèn)題:
 * 1.是會(huì)內(nèi)存泄露,因?yàn)閜ersenter一直持有Activity汤善,如果一個(gè)發(fā)了一個(gè)請(qǐng)求什猖,
 * 但是網(wǎng)絡(luò)有點(diǎn)慢,這個(gè)時(shí)候退出Activity红淡,那么請(qǐng)求回來(lái)后還是會(huì)調(diào)用
 * Activity的回調(diào)方法不狮,這里還是因?yàn)橐恢背钟械膯?wèn)題
 * 2.如果已經(jīng)退出了當(dāng)前界面,這個(gè)請(qǐng)求也沒(méi)有用了在旱,這個(gè)時(shí)候我們可以斷開(kāi)請(qǐng)求
 * <p>
 * 解決問(wèn)題:
 * 1.增加綁定和解綁的方法來(lái)解決內(nèi)存泄露和退出后還會(huì)回調(diào)的問(wèn)題
 * 2摇零、增加斷開(kāi)網(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("請(qǐng)求中,請(qǐng)稍后...");
    }
    @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)存泄露的問(wèn)題,但是這樣還是不完美桶蝎,應(yīng)用中肯定不可能只有一個(gè)模塊驻仅,每個(gè)模塊都對(duì)應(yīng)著一個(gè)V層和P層,那這樣的話每個(gè)Presenter中都要定義綁定和解綁的方法登渣,而Activity中對(duì)應(yīng)的也要調(diào)用這綁定和解綁的兩個(gè)方法噪服,代碼冗余。

簡(jiǎn)單抽象-解決MVP代碼冗余

針對(duì)這個(gè)問(wèn)題我們可以抽取出一個(gè)基類(lèi)的Presenter和一個(gè)基類(lèi)的Activity來(lái)做這個(gè)事情胜茧,讓子類(lèi)不用在寫(xiě)這些重復(fù)的代碼粘优。但是問(wèn)題又來(lái)了,既然是基類(lèi),肯定不止有一個(gè)子類(lèi)來(lái)繼承基類(lèi)敬飒,那么也就是說(shuō)子類(lèi)當(dāng)中定義的View接口和需要?jiǎng)?chuàng)建的Presenter都不相同邪铲,我們肯定在基類(lèi)當(dāng)中不能寫(xiě)死吧,那就使用泛型來(lái)設(shè)計(jì)无拗。

思路:

1.創(chuàng)建一個(gè)基類(lèi)View带到,讓所有View接口都必須實(shí)現(xiàn),這個(gè)View可以什么都不做只是用來(lái)約束類(lèi)型的
2.創(chuàng)建一個(gè)基類(lèi)的Presenter,在類(lèi)上規(guī)定View泛型英染,然后定義綁定和解綁的抽象方法揽惹,讓子類(lèi)去實(shí)現(xiàn),對(duì)外在提供一個(gè)獲取View的方法四康,

讓子類(lèi)直接通過(guò)方法來(lái)獲取View

3.創(chuàng)建一個(gè)基類(lèi)的Activity搪搏,聲明一個(gè)創(chuàng)建Presenter的抽象方法,因?yàn)橐獛妥宇?lèi)去綁定和解綁那么就需要拿到子類(lèi)的Presenter才行闪金,但是又不能隨便一個(gè)類(lèi)都能綁定的疯溺,因?yàn)橹挥谢?lèi)的Presenter中才定義了綁定和解綁的方法,所以同樣的在類(lèi)上可以聲明泛型在哎垦,方法上使用泛型來(lái)達(dá)到目的囱嫩。
4.修改Presenter和Activity中的代碼,各自繼承自己的基類(lèi)并去除重復(fù)代碼

實(shí)現(xiàn)步驟:

1.創(chuàng)建一個(gè)基類(lèi)View漏设,讓所有View接口都必須實(shí)現(xiàn)
/**
 * @author 
 * @date 2017/11/17
 * @description 所有mvpView的父接口
 */
public interface IMvpBaseView4 {
}
2.創(chuàng)建一個(gè)基類(lèi)的Presenter墨闲,在類(lèi)上規(guī)定View泛型,然后定義綁定和解綁的方法郑口,對(duì)外在提供一個(gè)獲取View的方法鸳碧,讓子類(lèi)直接通過(guò)方法來(lái)獲取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.創(chuàng)建一個(gè)基類(lèi)的Activity,聲明一個(gè)創(chuàng)建Presenter的抽象方法犬性,因?yàn)橐獛妥宇?lèi)去綁定和解綁那么就需要拿到子類(lèi)的Presenter才行瞻离,但是又不能隨便一個(gè)類(lèi)都能綁定的,因?yàn)橹挥谢?lèi)的Presenter中才定義了綁定和解綁的方法乒裆,所以同樣的在類(lèi)上可以聲明泛型在方法上使用泛型來(lái)達(dá)到目的
/**
 * @description MvpActivity
 * 指定子類(lèi)具體的View必須繼承自IMvpBaseView4
 * 指定子類(lèi)具體的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 子類(lèi)自己需要的Presenter
     */
    protected abstract P createPresenter();
    /**
     * 獲取Presenter
     * @return 返回子類(lèi)創(chuàng)建的Presenter
     */
    public P getPresenter() {
        return presenter;
    }
}
4.修改Presenter和Activity中的代碼琐脏,各自繼承自己的基類(lèi)并去除重復(fù)代碼

修改后的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();
        }
        //模擬網(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("請(qǐng)求中,請(qǐng)稍后...");
    }
    @Override
    public void resultSuccess(WeatherBean result) {
        //成功
        textView.setText(result.getWeatherinfo().toString());
    }
    @Override
    public void resultFailure(String result) {
        //失敗
        textView.setText(result);
    }
}

到這里完美了嗎缸兔?沒(méi)有,還可以再抽吹艇,來(lái)分析一下還有哪些不完美的地方以及如何再優(yōu)化惰蜜。

進(jìn)一步的優(yōu)化

高級(jí)抽象-使用注解、工廠模式受神、代理模式抛猖、策略模式整體解決代碼冗余、內(nèi)存泄露、Presenter生命周期以及數(shù)據(jù)存儲(chǔ)問(wèn)題

1.每個(gè)子類(lèi)都要重寫(xiě)父類(lèi)創(chuàng)建Presenter的方法财著,創(chuàng)建一個(gè)Presenter并返回联四,這一步我們也可以讓父類(lèi)幫忙干了,怎么做呢撑教?

我們可以采用注解的方式朝墩,在子類(lèi)上聲明一個(gè)注解并注明要?jiǎng)?chuàng)建的類(lèi)型,剩下的事情就讓父類(lèi)去做了,但是父類(lèi)得考慮如果子類(lèi)不想這么干怎么辦伟姐,那也還是不能寫(xiě)死吧收苏,可以使用策略模式加工廠模式來(lái)實(shí)現(xiàn),我們默認(rèn)使用這種注解的工廠 愤兵,但是如果子類(lèi)不喜歡可以通過(guò)父類(lèi)提供的一個(gè)方法來(lái)創(chuàng)建自己的工廠鹿霸。

2.Presenter真正的創(chuàng)建過(guò)程,我們可以將它放到真正使用Presenter的時(shí)候再創(chuàng)建秆乳,這樣的話可以稍微優(yōu)化一下性能問(wèn)題
3.界面有可能會(huì)意外銷(xiāo)毀并重建懦鼠,Activity、Fragment屹堰、View都可以在銷(xiāo)毀的時(shí)候通過(guò)onDestroy釋放一些資源并在onSaveInstanceState方法中存儲(chǔ)一些數(shù)據(jù)然后在重建的時(shí)候恢復(fù)肛冶,但是有可能Presenter中也需要釋放一些資源存儲(chǔ)一些數(shù)據(jù),那么上面的結(jié)構(gòu)就不能滿足了双藕,我們可以給Presenter增加生命周期的方法淑趾,讓Presenter和V層生命周期同步就可以做到了
4.第三步中我們又給Presenter加入了一些生命周期的方法,再加上Presenter的創(chuàng)建綁定和解綁的方法忧陪,那么如果我們?cè)趧?chuàng)建一個(gè)MvpFragment基類(lèi)扣泊,或者View的基類(lèi)那么這么多的代碼豈不是都要copy一份嗎,而且看起來(lái)也很不清晰嘶摊,這里我們可以采用代理模式來(lái)優(yōu)化一下延蟹。

好了下面來(lái)實(shí)現(xiàn):

1.我們既然要采用工廠模式才創(chuàng)建Presenter,那么我們首先來(lái)創(chuàng)建一個(gè)工廠接口
/**
 * @author 
 * @date 2017/11/17
 * @description Presenter工廠接口
 */
public interface PresenterMvpFactory<V extends BaseMvpView,P extends BaseMvpPresenter<V>> {
    /**
     * 創(chuàng)建Presenter的接口方法
     * @return 需要?jiǎng)?chuàng)建的Presenter
     */
    P createMvpPresenter();
}
2.然后我們需要?jiǎng)?chuàng)建一個(gè)默認(rèn)使用注解創(chuàng)建的工廠叶堆,那么首先要?jiǎng)?chuàng)建一個(gè)注解

注解:

/**
 * @description 標(biāo)注創(chuàng)建Presenter的注解
 */
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface CreatePresenter {
    Class<? extends BaseMvpPresenter> value();
}

注解工廠:

/**
 * @author 
 * @date 2017/11/17
 * @description Presenter工廠實(shí)現(xiàn)類(lèi)
 */
public class PresenterMvpFactoryImpl<V extends BaseMvpView, P extends BaseMvpPresenter<V>> implements PresenterMvpFactory<V, P> {
    /**
     * 需要?jiǎng)?chuàng)建的Presenter的類(lèi)型
     */
    private final Class<P> mPresenterClass;
    /**
     * 根據(jù)注解創(chuàng)建Presenter的工廠實(shí)現(xiàn)類(lèi)
     * @param viewClazz 需要?jiǎng)?chuàng)建Presenter的V層實(shí)現(xiàn)類(lèi)
     * @param <V> 當(dāng)前View實(shí)現(xiàn)的接口類(lèi)型
     * @param <P> 當(dāng)前要?jiǎng)?chuàng)建的Presenter類(lèi)型
     * @return 工廠類(lèi)
     */
    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.我們說(shuō)了不能寫(xiě)死這個(gè)工廠,那么我們需要使用者可以自定義虱颗,那么我們還需要給使用者提供一個(gè)設(shè)置的方法沥匈,我們定義一個(gè)接口提供設(shè)置工廠、獲取工廠忘渔、獲取Presenter的方法高帖,然后讓V層來(lái)實(shí)現(xiàn)這個(gè)接口,這樣V層的子類(lèi)就可以通過(guò)相應(yīng)的方法使用了
/**
 * @author
 * @date 2017/11/20
 * @description 代理接口
 */
public interface PresenterProxyInterface<V extends BaseMvpView,P extends BaseMvpPresenter<V>> {
    /**
     * 設(shè)置創(chuàng)建Presenter的工廠
     * @param presenterFactory PresenterFactory類(lèi)型
     */
    void setPresenterFactory(PresenterMvpFactory<V,P> presenterFactory);
    /**
     * 獲取Presenter的工廠類(lèi)
     * @return 返回PresenterMvpFactory類(lèi)型
     */
    PresenterMvpFactory<V,P> getPresenterFactory();
    /**
     * 獲取創(chuàng)建的Presenter
     * @return 指定類(lèi)型的Presenter
     */
    P getMvpPresenter();
}
4.給Presenter增加生命周期的方法
/**
 * @author 
 * @date 2017/11/17
 * @description 所有Presenter的基類(lèi)畦粮,并不強(qiáng)制實(shí)現(xiàn)這些方法散址,有需要在重寫(xiě)
 */
public class BaseMvpPresenter<V extends BaseMvpView> {
    /**
     * V層view
     */
    private V mView;
    /**
     * Presenter被創(chuàng)建后調(diào)用
     *
     * @param savedState 被意外銷(xiāo)毀后重建后的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被銷(xiāo)毀時(shí)調(diào)用
     */
    public void onDestroyPersenter() {
        Log.e("perfect-mvp","P onDestroy = ");
    }
    /**
     * 在Presenter意外銷(xiāo)毀的時(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è)代理來(lái)管理Presenter的生命周期方法
/**
 * @author 
 * @date 2017/11/20
 * @description 代理實(shí)現(xiàn)類(lèi)瞪浸,用來(lái)管理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工廠類(lèi)
     */
    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的工廠類(lèi),這個(gè)方法只能在創(chuàng)建Presenter之前調(diào)用,也就是調(diào)用getMvpPresenter()之前吏祸,如果Presenter已經(jīng)創(chuàng)建則不能再修改
     *
     * @param presenterFactory PresenterFactory類(lèi)型
     */
    @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的工廠類(lèi)
     *
     * @return PresenterMvpFactory類(lèi)型
     */
    @Override
    public PresenterMvpFactory<V, P> getPresenterFactory() {
        return mFactory;
    }
    /**
     * 獲取創(chuàng)建的Presenter
     *
     * @return 指定類(lèi)型的Presenter
     * 如果之前創(chuàng)建過(guò),而且是以外銷(xiāo)毀則從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;
        }
    }
    /**
     * 銷(xiāo)毀Presenter持有的View
     */
    private void onDetachMvpView() {
        Log.e("perfect-mvp","Proxy onDetachMvpView = ");
        if (mPresenter != null && mIsAttchView) {
            mPresenter.onDetachMvpView();
            mIsAttchView = false;
        }
    }
    /**
     * 銷(xiāo)毀Presenter
     */
    public void onDestroy() {
        Log.e("perfect-mvp","Proxy onDestroy = ");
        if (mPresenter != null ) {
            onDetachMvpView();
            mPresenter.onDestroyPersenter();
            mPresenter = null;
        }
    }
    /**
     * 意外銷(xiāo)毀的時(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í)存儲(chǔ)的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 
 * @date 2017/11/17
 * @description 繼承自Activity的基類(lèi)MvpActivity
 * 使用代理模式來(lái)代理Presenter的創(chuàng)建含滴、銷(xiāo)毀、綁定丐巫、解綁以及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)建被代理對(duì)象,傳入默認(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層上定義需要?jiǎng)?chuàng)建的Presenter,聲明自己模塊具體的View接口類(lèi)型和Presenter類(lèi)型递胧,最后實(shí)現(xiàn)自己View接口就ok了碑韵,還有就是如果要設(shè)置自己的Presenter創(chuàng)建工廠,必須在調(diào)用onResume方法和getMvpPresenter方法之前設(shè)置
//聲明需要?jiǎng)?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 測(cè)試  = " + 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("請(qǐng)求中,請(qǐng)稍后...");
    }
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.e("perfect-mvp","MainActivity onSaveInstanceState 測(cè)試");
        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í)候如果界面意外銷(xiāo)毀,Presenter可以通過(guò)重寫(xiě)以下方法進(jìn)行釋放資源祝闻,存儲(chǔ)數(shù)據(jù),和恢復(fù)數(shù)據(jù)遗菠,例如:
@Override
public void onCreatePersenter(@Nullable Bundle savedState) {
    super.onCreatePersenter(savedState);
    if(savedState != null){
        Log.e("perfect-mvp","RequestPresenter5  onCreatePersenter 測(cè)試  = " + savedState.getString("test2") );
    }
}
@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    Log.e("perfect-mvp","RequestPresenter5  onSaveInstanceState 測(cè)試 " );
    outState.putString("test2","test_save2");
}
@Override
public void onDestroyPersenter() {
    super.onDestroyPersenter();
}

哦了联喘!大功告成,perfect辙纬!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末豁遭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子贺拣,更是在濱河造成了極大的恐慌蓖谢,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件譬涡,死亡現(xiàn)場(chǎng)離奇詭異闪幽,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)涡匀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)沟使,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人渊跋,你說(shuō)我怎么就攤上這事腊嗡。” “怎么了拾酝?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵燕少,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我蒿囤,道長(zhǎng)客们,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任材诽,我火速辦了婚禮底挫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘脸侥。我一直安慰自己建邓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布睁枕。 她就那樣靜靜地躺著官边,像睡著了一般。 火紅的嫁衣襯著肌膚如雪外遇。 梳的紋絲不亂的頭發(fā)上注簿,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音跳仿,去河邊找鬼诡渴。 笑死,一個(gè)胖子當(dāng)著我的面吹牛菲语,可吹牛的內(nèi)容都是我干的妄辩。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼谨究,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼恩袱!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起胶哲,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤畔塔,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后鸯屿,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體澈吨,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年寄摆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谅辣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡婶恼,死狀恐怖桑阶,靈堂內(nèi)的尸體忽然破棺而出柏副,到底是詐尸還是另有隱情,我是刑警寧澤蚣录,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布割择,位于F島的核電站,受9級(jí)特大地震影響萎河,放射性物質(zhì)發(fā)生泄漏荔泳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一虐杯、第九天 我趴在偏房一處隱蔽的房頂上張望玛歌。 院中可真熱鬧,春花似錦擎椰、人聲如沸支子。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)译荞。三九已至,卻和暖如春休弃,著一層夾襖步出監(jiān)牢的瞬間吞歼,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工塔猾, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留篙骡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓丈甸,卻偏偏與公主長(zhǎng)得像琉预,于是被迫代替她去往敵國(guó)和親担汤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子光绕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355