一時興起的MVP+RxJava+Retrofit的封裝錄

MVP介紹:數據庫

MVP 全稱:Model-View-Presenter ;MVP 是從經典的模式MVC演變而來,它們的基本思想有相通的地方:Controller/Presenter負責邏輯的處理,Model提供數據,View負責顯示。網絡

RxJava介紹:框架

RxJava 在 GitHub 主頁上的自我介紹是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一個在 Java VM 上使用可觀測的序列來組成異步的、基於事件的程序的庫)。這就是 RxJava ,歸納得很是精準。對RxJava不熟悉的能夠看下https://gank.io/post/560e15be2dca930e00da1083這篇文章(我也不是很熟悉,拿來就用而已,手動攤手)。
異步

Retrofit介紹:async

Retrofit 其實至關簡單,簡單到源碼只有37個文件,其中22個文件是註解還都和HTTP有關,真正暴露給用戶的類並很少,因此我看了一遍 官方教程 大多數情景就能夠無障礙使用,若是你尚未看過,能夠先去看看,雖然是英文,但代碼纔是最好的教程不是麼?固然本篇文章會介紹得詳細一點,不能寫一篇水文,畢竟我給它命名爲《你真的會用Retrofit2嗎?Retrofit2徹底教程》。附上連接  https://www.jianshu.com/p/308f3c54abdd
 
進入正題吧,咱們首先來嘗試搭建一個MVP框架:
一、從View開始,新建一個BaseView接口,定義一下View層通用的方法;
public interface BaseView {
    /**
     * 顯示正在加載view
     */
    void showLoading();
    /**
     * 關閉正在加載view
     */
    void hideLoading();
    /**
     * 顯示提示
     * @param msg
     */
    void showToast(String msg, int length);
    /**
     * 顯示請求錯誤提示
     */
    void showErr(String errMsg);
    /**
     * 獲取上下文
     * @return 上下文
     */
    Context getContext();
}

好比如今有個登陸需求須要實現,新建一個LoginView,並繼承BaseView,使各功能View能自行實現本身的需求;ide

public interface LoginView extends BaseView {

    void loginSuccess();

    void loginFailure();

}

OK,咱們如今有了登陸模塊的View了,那麼,咱們能夠在相關登陸模塊的Activitiy,Fragment上實現該LoginView,例如:post

public class LoginActivity extends BaseActivity<LoginPresenter> implements LoginView{
    @Override
    public void loginSuccess() { } 

    @Override 
    public void loginFailure() { } 
}

好的,那麼咱們的LoginActivity就實現了咱們的LoginView功能了,BaseActivity待會會介紹;ui

View大概就這麼多,能夠根據具體的功能需求添加刪除;this

二、Presenter層:由上文提到的,負責邏輯處理;spa

一樣,新建一個BasePresenter類,由於presenter層級的操做是基於View層的,咱們須要在BasePresenter每一步操做前判斷咱們的view是否存在;

public class BasePresenter<V extends BaseView> {

    private V view;

    /**
     * 綁定view,通常在初始化中調用該方法
     */
    public void attachView(V view){
        this.view = view;
    }

    /**
     * 斷開view,通常在onDestroy中調用
     */
    public void detachView(){
        this.view = null;
    }

    /**
     * 是否與View創建鏈接
     * 每次調用業務請求的時候都要出先調用方法檢查是否與View創建鏈接
     */
    public boolean isViewAttached(){
        return view != null;
    }

    /**
     * 獲取鏈接的view
     */
    public V getView(){
        return this.view;
    }

    public Context getContext(){
        return this.view.getContext();
    }

}

如上圖,咱們能夠經過isViewAttached判斷view是否存在,若是view已銷燬,咱們的邏輯處理也不必繼續下去,進行相對應的銷燬工做便可;

OK,一樣咱們來實現功能Presenter,按照View的如今,咱們也實現一個登陸模塊的Presenter,新建一個LoginPresenter抽象類,並將對應的View以泛型參數聲明:

public abstract class LoginPresenter extends BasePresenter<LoginView> {

    /**
     * 登陸方法
     */
    public abstract void login(String phoneNum, String password);

}

而後,咱們將具體實現LoginPresenter,新建一個LoginPresenterImpl類,並繼承LoginPresenter;

public class LoginPresenterImpl extends LoginPresenter {

    @Override
    public void login(String phoneNum, String password) {
        if (isViewAttached()) {
            // 實現Login功能
        }
    }
}

Ok,如今咱們回頭來看LoginActivity,將咱們對應功能Presenter以泛型參數傳入

LoginActivity extends BaseActivity<LoginPresenter>

三、來看看BaseActivity,直接上代碼:

public abstract class BaseActivity<T extends BasePresenter> extends FragmentActivity implements BaseView {

    protected T mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setupContentView();
        initView();
        createPresenterAndAttachView();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mPresenter != null) {
            mPresenter.detachView();
        }
    }

    @Override
    public void showLoading() {
        Views.getInstance().showTipDialog(Views.TIPDIALOG_LOADING, this);
    }

    @Override
    public void hideLoading() {
        Views.getInstance().closeTipDialog();
    }

    @Override
    public void showToast(String msg, int length) {
        runOnUiThread(() -> Toast.makeText(getContext(), msg, length).show());
    }

    @Override
    public void showErr(String errMsg) {
        showToast(errMsg, Toast.LENGTH_LONG);
    }

    @Override
    public Context getContext() {
        return BaseActivity.this;
    }

    protected abstract void createPresenterAndAttachView();

    protected abstract void setupContentView();

    protected abstract void initView();
}

BaseActivity實現BaseView,將公共功能實現一下,同時咱們的Presenter在onDestroy()上將view解綁,同時我也寫了幾個抽象方法,createPresenterAndAttachView()在該方法中建立Presenter並進行view的鏈接工做,

其餘就無關緊要啦,根據本身的想法走吧。

好了,咱們如今差很少能夠用起來了。來看看LoginActivity的具體實現:

public class LoginActivity extends BaseActivity<LoginPresenter> implements LoginView, View.OnClickListener {

    @Override
    protected void createPresenterAndAttachView() {
        // 實例化Presenter
        mPresenter = new LoginPresenterImpl();
        // view創建鏈接
        mPresenter.attachView(this);
    }

    @Override
    protected void setupContentView() {
        setContentView(R.layout.activity_login);
    }

    @Override
    protected void initView() {
        // 初始化界面
    }

    @Override
    public void loginSuccess() {
        // 登陸成功
    }

    @Override
    public void loginFailure() {
        // 登陸失敗
    }

    @Override
    public void onClick(View view) {

    }
}
    

四、上面彷佛還少了個Model層,Model層主要是負責數據,如網絡訪問,數據庫查詢等操做,該層沒有進一步進行封裝了,先來看看Presenter層裏是怎樣跟Model層交互的;

public class LoginPresenterImpl extends LoginPresenter {

    @Override
    public void login(String phoneNum, String password) {
        if (isViewAttached()) {
            Map<String, Object> params = new HashMap<>();
            params.put("phoneNum", phoneNum);
            params.put("password", password);
            UserModel.login(getContext(), params, new Callback<LoginResponse>() {
                @Override
                public void onSuccess(LoginResponse data) {

                }

                @Override
                public void onFailure(int errCode, String msg) {

                }
            });
        }
    }

}

如上圖,在Presenter具體的邏輯實現中,咱們只是簡單的調用了Model層進行具體的數據操做;

讓咱們看看UserModel是怎樣作的:

/**
 * 用戶Model
 */
public final class UserModel {

    /**
     * 登陸
     * @param params
     * @param callback
     */
    public static void login(Context context, Map<String, Object> params, Callback<LoginResponse> callback) {
        RetrofitManager.getInstance().createService(UserApi.class).login(params)
                .compose(RetrofitManager.getInstance().ioMainSchedulers())
                .subscribe(new BaseObserver<>(context, callback));
    }
}

LoginResponse是服務端返回的實體數據,具體如何造就看你服務端具體返回什麼了;

Callback是一個通用的接口,以下:

public interface Callback<T> {

    /**
     * 數據請求成功
     *
     * @param data
     */
    void onSuccess(T data);

    /**
     * 使用網絡API接口請求方式時,雖然已經請求成功可是由
     * 於{@code msg}的緣由沒法正常返回數據。
     */
    void onFailure(int errCode, String msg);
}

五、終於到RxJava和Retrofit的使用了,RetrofitManager是一個Retrofit管理類

/**
 * Retrofit管理類
 */
public final class RetrofitManager {


    private Retrofit retrofit;

    public static RetrofitManager getInstance() {
        return RetrofitHelper.manager;
    }

    private RetrofitManager() {
        retrofit = new Retrofit.Builder()
                .baseUrl(HttpConstants.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
    }

    private static class RetrofitHelper {
        private static final RetrofitManager manager = new RetrofitManager();
    }

    public <T> T createService(Class<T> clazz) {
        return retrofit.create(clazz);
    }

    public <T> ObservableTransformer<T, T> ioMainSchedulers() {
        return upstream -> upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
    }
}

主要就是實現一個單例模式,而後配合RxJava進行使用,以下login接口:

public interface UserApi {

    @FormUrlEncoded
    @POST(HttpConstants.LOGIN)
    Observable<BaseResponse<LoginResponse>> login(@FieldMap Map<String, Object> params);
}

Retrofit+RxJava主要是接口返回參數爲RxJava的Observable,就是這麼簡單,深刻的我也還沒去研究,先用起來吧。

Ok,大概就是這樣了。這樣的話,咱們的各層級進行了應有的解耦,代碼也乾淨了不少。可是,代碼量我以爲是多了的。

本身隨手記錄的一些內容,至關因而複習了下RxJava,Retrofit的使用和Mvp的概念,不喜勿噴。

相關文章
相關標籤/搜索