【Android架構(gòu)】基于MVP模式的Retrofit2+RXjava封裝(一)

前言

最近有個新項目要做钾菊,搭建框架的時候溃槐,順便梳理了下MVP模式匣砖,特此記錄,歡迎大家指正昏滴。

一 猴鲫、首先是依賴

    compile 'com.google.code.gson:gson:2.8.0'
    compile 'com.squareup.okhttp3:okhttp:3.4.1'
    compile 'com.squareup.retrofit2:retrofit:2.3.0'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    compile 'io.reactivex.rxjava2:rxjava:2.1.5'
    //ConverterFactory的String依賴包
    compile 'com.squareup.retrofit2:converter-scalars:2.3.0'
    //ConverterFactory的Gson依賴包
    compile 'com.squareup.retrofit2:converter-gson:2.3.0'
    //CallAdapterFactory的Rx依賴包
    compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'

二、ApiServer谣殊,定義了一些接口

public interface ApiServer {
    @POST("shopping_login.htm")
    Observable<String> LoginByRx(@Field("username") String username, @Field("password") String password);

}

三拂共、ApiRetrofit,初始化Retrofit姻几、OkHttpClient宜狐,加入了攔截器

public class ApiRetrofit {

    public final String BASE_SERVER_URL = "https://wawa-api.vchangyi.com/";

    private static ApiRetrofit apiRetrofit;
    private Retrofit retrofit;
    private OkHttpClient client;
    private ApiServer apiServer;

    private String TAG = "ApiRetrofit";

    /**
     * 請求訪問quest
     * response攔截器
     */
    private Interceptor interceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            long startTime = System.currentTimeMillis();
            Response response = chain.proceed(chain.request());
            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;
            MediaType mediaType = response.body().contentType();
            String content = response.body().string();
            Log.e(TAG, "----------Request Start----------------");
            Log.e(TAG, "| " + request.toString() + request.headers().toString());
            Log.e(TAG, "| Response:" + content);
            Log.e(TAG, "----------Request End:" + duration + "毫秒----------");
            return response.newBuilder()
                    .body(ResponseBody.create(mediaType, content))
                    .build();
        }
    };


    public ApiRetrofit() {
        client = new OkHttpClient.Builder()
                //添加log攔截器
                .addInterceptor(interceptor)
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .build();

        retrofit = new Retrofit.Builder()
                .baseUrl(BASE_SERVER_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addConverterFactory(ScalarsConverterFactory.create())
                //支持RxJava2
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(client)
                .build();

        apiServer = retrofit.create(ApiServer.class);
    }

    public static ApiRetrofit getInstance() {
        if (apiRetrofit == null) {
            synchronized (Object.class) {
                if (apiRetrofit == null) {
                    apiRetrofit = new ApiRetrofit();
                }
            }
        }
        return apiRetrofit;
    }

    public ApiServer getApiService() {
        return apiServer;
    }

}

四、基類
1.BaseView蛇捌,其中定義了常用的接口

public interface BaseView {
    /**
     * 顯示dialog
     */
    void showLoading();

    /**
     * 隱藏 dialog
     */

    void hideLoading();

    /**
     * 顯示錯誤信息
     *
     * @param msg
     */
    void showError(String msg);

    /**
     * 錯誤碼
     */
    void onErrorCode(BaseModel model);
}

2.BaseModel

public class BaseModel<T> implements Serializable {
    private int errcode;
    private String errmsg;
    private T result;

    public int getErrcode() {
        return errcode;
    }

    public void setErrcode(int errcode) {
        this.errcode = errcode;
    }

    public String getErrmsg() {
        return errmsg;
    }

    public void setErrmsg(String errmsg) {
        this.errmsg = errmsg;
    }

    public T getResult() {
        return result;
    }

    public void setResult(T result) {
        this.result = result;
    }
}

3.BasePresenter

public class BasePresenter<V extends BaseView> {

    private CompositeDisposable compositeDisposable;


    public V baseView;

    protected ApiServer apiServer = ApiRetrofit.getInstance().getApiService();

    public BasePresenter(V baseView) {

        this.baseView = baseView;
    }

    /**
     * 解除綁定
     */
    public void detachView() {
        baseView = null;
        removeDisposable();
    }

    /**
     * 返回 view
     *
     * @return
     */
    public V getBaseView() {
        return baseView;
    }


    public void addDisposable(Observable<?> observable, BaseObserver observer) {
        if (compositeDisposable == null) {
            compositeDisposable = new CompositeDisposable();
        }
        compositeDisposable.add(observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeWith(observer));


    }

    public void removeDisposable() {
        if (compositeDisposable != null) {
            compositeDisposable.dispose();
        }
    }

}

4.BaseObserver抚恒,主要處理了常見的錯誤

public abstract class BaseObserver<T> extends DisposableObserver<T> {
    protected BaseView view;
    /**
     * 解析數(shù)據(jù)失敗
     */
    public static final int PARSE_ERROR = 1001;
    /**
     * 網(wǎng)絡(luò)問題
     */
    public static final int BAD_NETWORK = 1002;
    /**
     * 連接錯誤
     */
    public static final int CONNECT_ERROR = 1003;
    /**
     * 連接超時
     */
    public static final int CONNECT_TIMEOUT = 1004;


    public BaseObserver(BaseView view) {
        this.view = view;
    }

    @Override
    protected void onStart() {
        if (view != null) {
            view.showLoading();
        }
    }

    @Override
    public void onNext(T o) {
        try {
            BaseModel model = (BaseModel) o;
            if (model.getErrcode() == 0) {
                onSuccess(o);
            } else {
                if (view != null) {
                    view.onErrorCode(model);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            onError(e.toString());
        }


    }

    @Override
    public void onError(Throwable e) {
        if (view != null) {
            view.hideLoading();
        }
        if (e instanceof HttpException) {
            //   HTTP錯誤
            onException(BAD_NETWORK);
        } else if (e instanceof ConnectException
                || e instanceof UnknownHostException) {
            //   連接錯誤
            onException(CONNECT_ERROR);
        } else if (e instanceof InterruptedIOException) {
            //  連接超時
            onException(CONNECT_TIMEOUT);
        } else if (e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException) {
            //  解析錯誤
            onException(PARSE_ERROR);
        } else {
            if (e != null) {
                onError(e.toString());
            } else {
                onError("未知錯誤");
            }
        }

    }

    private void onException(int unknownError) {
        switch (unknownError) {
            case CONNECT_ERROR:
                onError("連接錯誤");
                break;

            case CONNECT_TIMEOUT:
                onError("連接超時");
                break;

            case BAD_NETWORK:
                onError("網(wǎng)絡(luò)問題");
                break;

            case PARSE_ERROR:
                onError("解析數(shù)據(jù)失敗");
                break;

            default:
                break;
        }
    }


    @Override
    public void onComplete() {
        if (view != null) {
            view.hideLoading();
        }

    }
    public abstract void onSuccess(T o);

    public abstract void onError(String msg);
}

5.BaseActivity,實現(xiàn)BaseView络拌,統(tǒng)一處理了Presenter的解綁與綁定俭驮。

public abstract class BaseActivity<P extends BasePresenter> extends AppCompatActivity implements BaseView {
    public Context context;
    private ProgressDialog dialog;
    public Toast toast;
    protected P presenter;

    protected abstract P createPresenter();

    protected abstract int getLayoutId();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context = this;
        setContentView(getLayoutId());
        presenter = createPresenter();
        initView();
        initData();
    }

    public void initData() {
    }

    public void initView() {
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //銷毀時,解除綁定
        if (presenter != null) {
            presenter.detachView();
        }
    }

   /**
     * @param s
     */
    public void showtoast(String s) {
        if (toast == null) {
            toast = Toast.makeText(getApplicationContext(), s, Toast.LENGTH_LONG);
        }
        toast.show();
    }

    private void closeLoadingDialog() {
        if (dialog != null && dialog.isShowing()) {
            dialog.dismiss();
        }
    }


    private void showLoadingDialog() {

        if (dialog == null) {
            dialog = new ProgressDialog(context);
        }
        dialog.setCancelable(false);
        dialog.show();
    }

    @Override
    public void showLoading() {
        showLoadingDialog();
    }


    @Override
    public void hideLoading() {
        closeLoadingDialog();
    }


    @Override
    public void showError(String msg) {
        showtoast(msg);
    }

    @Override
    public void onErrorCode(BaseModel model) {
    }

    @Override
    public void showLoadingFileDialog() {
        showFileDialog();
    }

    @Override
    public void hideLoadingFileDialog() {
        hideFileDialog();
    }

    @Override
    public void onProgress(long totalSize, long downSize) {
        if (dialog != null) {
            dialog.setProgress((int) (downSize * 100 / totalSize));
        }
    }
}

如上春贸,框架已經(jīng)搭建好了混萝,讓我們來看看在實際項目中怎么用遗遵。

我們來模擬登陸

1.定義LoginView 繼承于BaseView

public interface LoginView extends BaseView {
    void onLoginSucc();
}

2.定義LoginPresenter繼承于BasePresenter

public class LoginPresenter extends BasePresenter<LoginView> {
    public LoginPresenter(LoginView baseView) {
        super(baseView);
    }

    public void login(String name, String pwd) {

        addDisposable(apiServer.LoginByRx(name, pwd), new BaseObserver(baseView) {
            @Override
            public void onSuccess(Object o) {
                baseView.onLoginSucc();

            }

            @Override
            public void onError(String msg) {
                baseView.showError(msg);

            }
        });
    }
}

3.LoginActivity 中使用

public class LoginActivity extends BaseActivity<LoginPresenter> implements LoginView {

    private AutoCompleteTextView mEmailView;
    private EditText mPasswordView;

    @Override
    protected LoginPresenter createPresenter() {
        return new LoginPresenter(this);
    }

    @Override
    protected int getLayoutId() {
        return R.layout.activity_login;
    }

    @Override
    public void initView() {
        mEmailView = (AutoCompleteTextView) findViewById(R.id.email);
        mPasswordView = (EditText) findViewById(R.id.password);
        Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);
        mEmailSignInButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                //示例代碼,示例接口
                presenter.login(mEmailView.getText().toString(), mPasswordView.getText().toString());

            }
        });
    }

    @Override
    public void onLoginSucc() {
        //Login Succ

        showtoast("登錄成功");

    }
}

項目地址GitHub

總結(jié):以上就是MVP的實現(xiàn)譬圣,MVP的框架很多瓮恭,適合自己就好雄坪。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末厘熟,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子维哈,更是在濱河造成了極大的恐慌绳姨,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阔挠,死亡現(xiàn)場離奇詭異飘庄,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)购撼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門跪削,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人迂求,你說我怎么就攤上這事碾盐。” “怎么了揩局?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵毫玖,是天一觀的道長。 經(jīng)常有香客問我凌盯,道長付枫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任驰怎,我火速辦了婚禮阐滩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘县忌。我一直安慰自己掂榔,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布芹枷。 她就那樣靜靜地躺著衅疙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鸳慈。 梳的紋絲不亂的頭發(fā)上饱溢,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機(jī)與錄音走芋,去河邊找鬼潘鲫。 笑死肋杖,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的状植。 我是一名探鬼主播浊竟,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼津畸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起后频,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎暖途,沒想到半個月后卑惜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡驻售,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年芋浮,在試婚紗的時候發(fā)現(xiàn)自己被綠了抱环。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纸巷。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡瘤旨,死狀恐怖梯啤,靈堂內(nèi)的尸體忽然破棺而出存哲,到底是詐尸還是另有隱情,我是刑警寧澤祟偷,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布修肠,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏莽鸭。R本人自食惡果不足惜吃靠,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望巢块。 院中可真熱鬧,春花似錦氮兵、人聲如沸歹鱼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽掺涛。三九已至,卻和暖如春秧廉,著一層夾襖步出監(jiān)牢的瞬間拣帽,已是汗流浹背疼电。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工蔽豺, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留拧粪,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓可霎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拾因。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容