mvp+rxjava2+retrofit2專案框架demo

isJoker發表於2017-12-19

上個專案忙完了第一版,在此對上個專案的架構總結下,不斷總結分析,才能發現結構的短板,才能搭出屬於自己的最完美的架構。


1.分包

------我的分包如下圖:

這裡寫圖片描述

adapter:放一些adapter類,屬於view層的

api:放一些網路請求相關的類,如配置retrofit

base:放一些activity、fragment、presenter的基類

common:放一些全域性都會用到的公共類,如application

model:我的model層只放了bean類,分為request和response,跟傳統mvp的model不同,傳統mvp的model層是請求網路資料,然後p層拿到m層和v層的引用,使m層和v層互動,但那樣程式碼量太多了,每一個請求都要建立一個model類,為了簡介,我就把請求網路資料直接放在了p層,在後面的程式碼中你會看到。

presenter:放presenter類

utils:放一些工具類

viewinterface:放view介面類

viewimpl:放view實現類

widget:放自定義view

------因為這個專案不大,介面不多,所以我採用此種分包,如果專案功能模組比較多的話,按功能模組分包比較好,結構清晰。下圖是我之前做過的功能模組比較多的專案:

這裡寫圖片描述


2.mvp

自2016年起,mvp框架一度興起,越來越多的安卓開發者都選擇用mvp框架來開發app。mvp結合rxjava和retrofit 簡直爽的不要不要的,自從用了mvp結合rxjava和retrofi,程式碼簡潔了,邏輯也清晰了,呼叫也優雅了,維護成本也低利了。公司的這個專案我是用mvp+rxjava2+retrofit2+butterknife。

此mvp框架用到了註解、工廠模式、代理模式來解決程式碼冗餘、記憶體洩露(P在請求網路資料時,view(Activity或者Fragment)介面銷燬,導致P仍然持有view的引用)、presenter生命週期以及資料儲存問題;通過泛型將view和presenter繫結,可在view中直接呼叫getPresenter()獲取presenter來請求網路資料,在presenter中可以直接通過呼叫getView()獲取view來更新介面。請求網路用的是封裝後的rxjava+retrofit,新增了網路請求和響應攔截器,網路請求和響應json可直接在在Android Studio中的Logcat中一目瞭然。

具體的原始碼實現我就不一一介紹了,感興趣的朋友可以下載原始碼,自行檢視;框架原始碼連結(https://github.com/isJoker/R2R2Mvp)

3.使用

你的api

public interface WApi {

    //獲取電影列表
    @POST("/PageSubArea/TrailerList.api")
    Flowable<MoiveListResponse> getMoiveList();

}
複製程式碼

首先,先定義一個view介面IMoiveListView

/**
 * Created by JokerWan on 2017/12/11.
 * WeChat: wjc398556712
 * Function:
 */
public interface IMoiveListView extends IWanBaseView{

    void onLoading();

    void onLoadSucess(MoiveListResponse moiveListResponse);

    void onLoadFail(String msg);
}
複製程式碼

Activity的使用(Fragment的使用類似),通過註解 @CreatePresenter建立Presenter

/**
 * Created by JokerWan on 2017/12/11.
 * WeChat: wjc398556712
 * Function:
 */
@CreatePresenter(MoiveListPresenter.class)
public class MainActivity extends AWanBaseActivity<IMoiveListView,MoiveListPresenter>
        implements IMoiveListView {

    @BindView(R.id.tv_moive_name)
    TextView tvMoiveName;
    @BindView(R.id.img_moive)
    ImageView imgMoive;

    @Override
    public int getViewLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    public void initData(Bundle savedInstanceState) {
        if (null != savedInstanceState) {
            // TODO: 2017/12/11 資料恢復
        }
        getPresenter().getMoiveList();

    }

    @Override
    public void onLoading() {
        tvMoiveName.setText("資料載入中,請稍後...");
    }

    @Override
    public void onLoadSucess(MoiveListResponse     moiveListResponse) {
        MoiveListResponse.TrailersBean trailersBean = moiveListResponse.getTrailers().get(1);
        tvMoiveName.setText(trailersBean.getMovieName());
        Glide
            .with(this)
            .load(trailersBean.getCoverImg())
            .into(imgMoive);
    }

    @Override
    public void onLoadFail(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }
}

複製程式碼

presenter的使用

/**
 * Created by JokerWan on 2017/12/11.
 * WeChat: wjc398556712
 * Function:
 */

public class MoiveListPresenter extends AWanBasePresenter<IMoiveListView> {

    public void getMoiveList(){

        getView().onLoading();

        wApi.getMoiveList()
                .compose(ApiUtils.getScheduler())
                .subscribe(new ApiSubscriber<MoiveListResponse>() {
                    @Override
                    public void onNext(MoiveListResponse moiveListResponse) {
                        if(moiveListResponse != null) {
                            getView().onLoadSucess(moiveListResponse);
                        }
                    }

                    @Override
                    public void onError(Throwable t) {
                        getView().onLoadFail(t.getMessage());
                    }
                });
    }
}
複製程式碼

4.demo執行後的效果

這裡寫圖片描述

相關文章