RxJava2+Retrofit2+RxLifecycle2使用MVP模式構建項目

眼下Retrofit+RxJava搭配的網絡請求框架非常流行,本着學習的態度,寫了一個相關的demo。寫着寫着就想朝着搭建一個項目框架的方向走。因而使用了一下MVP模式。java

RxJava 確實挺好用,我的特別喜歡這種「流式」的代碼風格,邏輯很清晰,起碼提供了一種相對的規範,開發者按照對應的流程寫代碼,後期的維護和拓展會簡單不少。git

MVP模式簡單說就是爲了解耦,各行各職,閱讀代碼,拓展功能代價不會那麼大(或許有些人認爲不必用MVP,直接在activity/fragment中寫代碼就行了,那隻能說你沒遇到到過相對大一點的項目,或者沒遇到「實習生」寫代碼,那酸爽,看代碼會看得你懷疑人生)github

MVP

在使用MVC開發Android應用的時候,原理上api

  • View:對應於佈局文件xml
  • Model:業務邏輯和實體模型
  • Controllor:對應於Activity

可是寫代碼的時候,你就會發現,好多跟view相關的操做都在activity中實現完成了,致使activity既是Controllor又是View,網上有人稱爲是MV模式,也所以致使activity的代碼量特別大,1000+的代碼很常見 
後來,Presenter的出現,將Actvity,xml 視爲View層,Model不變,Presenter負責完成View層與Model層的交互。因而MVP是這樣的:服務器

  • View 對應於Activity,xml 負責View的繪製以及與用戶交互
  • Model 依然是業務邏輯和實體模型
  • Presenter 負責完成View於Model間的交互

在網上看了一下MVP的使用demo,挺多人將一個頁面須要完成的操做,以及須要用到的控件所有定義到相關的View接口中,示例:網絡

public interface IUserLoginView { String getUserName(); String getPassword(); void clearUserName(); void clearPassword(); void showLoading(); void hideLoading(); void toMainActivity(User user); void showFailedError(); }架構

我的以爲,這個有點蛋疼 
1.這樣view接口須要的方法太多了,有些實現(clearUserName())能夠放在activity中操做,第一不需將控件經過接口傳到Presenter中,第二我認爲這種算是對View的操做,仍是能夠看做View相關的。 
2.咱們很難知道一個界面都要實現些什麼方法(若是包括對某個控件內容清空等),可是咱們不難知道一個activity須要實現哪些主要的功能,好比登陸頁面就一個登陸功能,或者再加多一個第三方登陸咯。app

因此我以爲View接口中定義一些經常使用的方法,以及一些須要實現的方法就能夠了,經過回調內容,把控件賦值,數據展現等仍是放回在activity中操做,presenter只須要將對應的實體或者數據給activity就行了,activity怎麼展現,不用管,不關個人事情,作到各行各職。框架

或許有人會說,咦~你這都不是MVP,網上的MVP這些操做要放在presenter中的,這時我上去就給你一巴掌,咱們使用優秀的框架/架構是爲了學習它優秀的模式或者編碼風格,若是一味的循序漸進照着用,那將毫無心義!同時,咱們只有不斷改進,不斷推成出新才能使得技術不斷進步,若是前人不對MCV提出質疑,就不會有今天的MVP。ide

因此我以爲View的接口應該這樣 
一個BaseView,定義經常使用的方法,其餘頁面View接口繼承基類

public interface IBaseView { //顯示loading void showLoading(); //關閉loading void closeLoading(); //顯示吐司 void showToast(String msg); }

這個基類怎麼寫看項目須要,按照開發者各自需求編寫。

如今寫一個登陸的LoginView,繼承BaseView同時添加特定的接口

public interface ILoginView extends IBaseView { //顯示結果 void showResult(UserBean bean); }

這裏定義一個showResult(UserBean bean) 將User實體類傳給activity,用於展現用戶信息。

寫到這裏的時候的我突然更加堅決我所理解的MVP是對的,解耦嘛 
Presenter:負責獲取或者構建UserBean 
Activity:負責展現Presenter給過來的數據

以前看到過有人經過View接口將activity的控件幾乎「拷貝」到了presenter中,雖然實現了邏輯處理在Presenter,可是若是Presenter邏輯改動仍是會牽一髮動全身,要改動不少 
如今這種方式挺好的,負責構建數據,不參與展現,也方便單元測試。對,就是這樣的。

Retrofit2+RxJava2+RxLifecycle2

Retrofit+RxJava確實是一種很不錯的搭配,RxJava能夠指定運行的線程,在網絡請求時,開啓線程耗時操做,響應結果時切換爲主線程操做UI。很是漂亮,代碼風格也贊,我我的稱爲流式操做,從上到下一步步表明操做的主要邏輯,比起傳統的迷之嵌套,迷之縮進好多了。

咱們知道RxJava使用訂閱模式,若是沒有及時取消訂閱,會致使內存泄漏,這個是很是糟糕的行爲,固然解決方式也很簡單,在對應的生命週期取消訂閱就好,不過我仍是懷着好奇之心Github一下,果真已經有人對此做出了貢獻RxLifecycle 經過綁定生命週期能夠很方便的管理訂閱與取消訂閱。

Github: https://github.com/trello/RxLifecycle

Retrofit+RxJava的使用仍是挺簡單的,不過相對於你們已經用在項目的網絡請求框架,它仍是須要進行加工的。好比說錯誤處理,配合RxLifecycle使用,以及不少人會問的,在MVP中使用的時候怎麼取消訂閱。

先看下最簡單的使用 
接口代碼

public interface TestApi { @GET("v1/mobile/address/query") Observable<String> request(@QueryMap Map<String, Object> request); }

 使用代碼

Map<String, Object> request = new HashMap<>(); Retrofit retrofit = new Retrofit.Builder() .client(new OkHttpClient()) .baseUrl("http://apicloud.mob.com/") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); retrofit.create(TestApi.class).request(request).subscribe(new Observer<String>() { @Override public void onSubscribe(@NonNull Disposable d) { } @Override public void onNext(@NonNull String s) { } @Override public void onError(@NonNull Throwable e) { } @Override public void onComplete() { } });

代碼簡介,清晰,構建請求參數,構建被觀察者對象,以及傳入一個觀察者對象實現 
訂閱回調onSubscribe 也能夠是開始的操做 
成功回調onNext 
失敗回調onError 
監聽完成onComplete

或許開發者一眼就看出了onError 回調的對象是Throwable 這個不能忍啊,投入使用的框架確定得封裝,那就從這裏開始

錯誤處理

在常見的網絡請求框架中通常會有兩個回調函數

/** * 錯誤/異常回調 */ protected abstract void onError(ApiException e); /** * 成功回調 */ protected abstract void onSuccess(T response);

定義onError回調函數觸發的場景是:1.異常2.錯誤 
1.異常:請求異常,解析數據出錯,網絡異常等等 
2.錯誤:某一次請求邏輯錯誤,(例如:登陸錯誤) 
將上述兩種狀況交給onError回調函數處理 
在請求邏輯成功的時候觸發一個onSuccess函數。這樣監聽者就只須要兩個函數,一個失敗,一個成功,失敗提示給用戶,成功負責展現數據,跳轉頁面等

定義一個異常處理類ExceptionEngine

public class ExceptionEngine { public static final int UN_KNOWN_ERROR = 1000;//未知錯誤 public static final int ANALYTIC_SERVER_DATA_ERROR = 1001;//解析(服務器)數據錯誤 public static final int ANALYTIC_CLIENT_DATA_ERROR = 1002;//解析(客戶端)數據錯誤 public static final int CONNECT_ERROR = 1003;//網絡鏈接錯誤 public static final int TIME_OUT_ERROR = 1004;//網絡鏈接超時 public static ApiException handleException(Throwable e) { ApiException ex; if (e instanceof HttpException) { //HTTP錯誤 HttpException httpExc = (HttpException) e; ex = new ApiException(e, httpExc.code()); ex.setMsg("網絡錯誤"); //均視爲網絡錯誤 return ex; } else if (e instanceof ServerException) { //服務器返回的錯誤 ServerException serverExc = (ServerException) e; ex = new ApiException(serverExc, serverExc.getCode()); ex.setMsg(serverExc.getMsg()); return ex; } else if (e instanceof JsonParseException || e instanceof JSONException || e instanceof ParseException || e instanceof MalformedJsonException) { //解析數據錯誤 ex = new ApiException(e, ANALYTIC_SERVER_DATA_ERROR); ex.setMsg("解析錯誤"); return ex; } else if (e instanceof ConnectException) {//鏈接網絡錯誤 ex = new ApiException(e, CONNECT_ERROR); ex.setMsg("鏈接失敗"); return ex; } else if (e instanceof SocketTimeoutException) {//網絡超時 ex = new ApiException(e, TIME_OUT_ERROR); ex.setMsg("網絡超時"); return ex; } else { //未知錯誤 ex = new ApiException(e, UN_KNOWN_ERROR); ex.setMsg("未知錯誤"); return ex; } } }

異常處理類中,都是常見的錯誤類型,咱們經過解析Throwable轉換成統一的錯誤類ApiException

public class ApiException extends Exception { private int code;//錯誤碼 private String msg;//錯誤信息 public ApiException(Throwable throwable, int code) { super(throwable); this.code = code; } public ApiException(int code, String msg) { this.code = code; this.msg = msg; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }

這個類很是簡單,一個狀態碼,一個錯誤信息,方便咱們開發調試。

不過仔細看代碼的同窗會發現,ServerException這個是什麼鬼?「服務器返回的錯誤」?Throwable怎麼知道這個錯誤類型是ServerException

其實這個ServerException是咱們自定義的錯誤類型,通常咱們開發中都會跟服務器約定一種接口請求返回的數據。好比:

  • int code:表示接口請求狀態,0表示成功,-101表示密碼錯誤等等
  • String msg:表示接口請求返回的描述。success,」token過時」等等
  • Object result:成功是返回的數據

那麼咱們就能夠在解析服務端返回數據的時候,當code!=0,就拋出ServerException

public class ServerException extends RuntimeException { private int code; private String msg; public ServerException(int code, String msg) { this.code = code; this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; } }

OK,到這裏咱們常見的錯誤類型,異常等都處理完了,經過ExceptionEngine轉化爲統一的錯誤類型ApiException,在訂閱者回調onError(ApiException e)就能夠很方便知道錯誤的狀態碼以及對應的描述信息。

Observable observable = apiObservable .map(new ServerResultFunction()) .onErrorResumeNext(new HttpResultFunction<>()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread());

咱們使用onErrorResumeNext(new HttpResultFunction<>())操做符對Retrofit網絡請求拋出的Exception進行處理,咱們定義HttpResultFunction處理Retrofit拋出的Exception,經過ExceptionEngine轉化爲統一的錯誤類型ApiException

public class HttpResultFunction<T> implements Function<Throwable, Observable<T>> { @Override public Observable<T> apply(@NonNull Throwable throwable) throws Exception { //打印具體錯誤 LogUtils.e("HttpResultFunction:" + throwable); return Observable.error(ExceptionEngine.handleException(throwable)); } }

這一步是對錯誤,異常等的處理,若是某一個http請求沒有發生異常,或者網絡錯誤,就會走onNext回調。

前面咱們約定,將服務器返回的邏輯錯誤也歸類到onError。因此咱們在.map(new ServerResultFunction())操做符中處理服務器返回的結果是否正確(這裏指邏輯正確,即code==0),若是code!=0,就拋出ServerException

public class ServerResultFunction implements Function<HttpResponse, Object> { @Override public Object apply(@NonNull HttpResponse response) throws Exception { //打印服務器回傳結果 LogUtils.e(response.toString()); if (!response.isSuccess()) { throw new ServerException(response.getCode(), response.getMsg()); } return new Gson().toJson(response.getResult()); } }

解析服務器返回結果 HttpResponse,這個類由開發者自行設置,根據實際狀況來定義字段,這裏我假設後臺返回的字段有

String msg; int retCode; Object result;

/** * http響應參數實體類 * 經過Gson解析屬性名稱須要與服務器返回字段對應,或者使用註解@SerializedName * 備註:這裏與服務器約定返回格式 * * @author ZhongDaFeng */ public class HttpResponse { /** * 描述信息 */ @SerializedName("msg") private String msg; /** * 狀態碼 */ @SerializedName("retCode") private int code; /** * 數據對象[成功返回對象,失敗返回錯誤說明] */ @SerializedName("result") private Object result; /** * 是否成功(這裏約定200) * * @return */ public boolean isSuccess() { return code == 200 ? true : false; } public String toString() { String response = "[http response]" + "{\"code\": " + code + ",\"msg\":" + msg + ",\"result\":" + new Gson().toJson(result) + "}"; return response; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public Object getResult() { return result; } public void setResult(Object result) { this.result = result; } }

這裏Result咱們使用Object由於接口時通用的,服務端返回的接口類型也是多樣的,多是列表,也多是JSON對象,或者String字符串,因此這裏咱們使用Object,在數據解析的時候在轉化成爲具體的類型

嗯,錯誤處理搞定了,那就是簡單的封裝一下Retrofit 和RxJava以及使用RxLifecycle 
RxJava使用訂閱模式,那咱們就須要封裝一個被訂閱者,一個訂閱者,以及使用RxLifecycle自動管理訂閱的生命週期

構建Api接口類

public interface UserApi { @GET("user/login") Observable<HttpResponse> login(@QueryMap Map<String, Object> request); }

構建Retrofit工具類獲取retrofit實例

public class RetrofitUtils { /** * 接口地址 */ public static final String BASE_API = "http://apicloud.mob.com/"; public static final int CONNECT_TIME_OUT = 30;//鏈接超時時長x秒 public static final int READ_TIME_OUT = 30;//讀數據超時時長x秒 public static final int WRITE_TIME_OUT = 30;//寫數據接超時時長x秒 private static RetrofitUtils mInstance = null; private RetrofitUtils() { } public static RetrofitUtils get() { if (mInstance == null) { synchronized (RetrofitUtils.class) { if (mInstance == null) { mInstance = new RetrofitUtils(); } } } return mInstance; } /** * 設置okHttp * * @author ZhongDaFeng */ private static OkHttpClient okHttpClient() { //開啓Log HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { @Override public void log(String message) { LogUtils.e("okHttp:" + message); } }); logging.setLevel(HttpLoggingInterceptor.Level.BASIC); OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(CONNECT_TIME_OUT, TimeUnit.SECONDS) .writeTimeout(WRITE_TIME_OUT, TimeUnit.SECONDS) .readTimeout(READ_TIME_OUT, TimeUnit.SECONDS) .addInterceptor(logging) .build(); return client; } /** * 獲取Retrofit * * @author ZhongDaFeng */ public Retrofit retrofit() { Retrofit retrofit = new Retrofit.Builder() .client(okHttpClient()) .baseUrl(BASE_API) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); return retrofit; } }

構建網絡請求(被訂閱對象)

/** * 適用Retrofit網絡請求Observable(被監聽者) * * @author ZhongDaFeng */ public class HttpRxObservable { /** * 獲取被監聽者 * 備註:網絡請求Observable構建 * data:網絡請求參數 * <h1>補充說明</h1> * 傳入LifecycleProvider自動管理生命週期,避免內存溢出 * 備註:須要繼承RxActivity.../RxFragment... * * @author ZhongDaFeng */ public static Observable getObservable(Observable<HttpResponse> apiObservable, LifecycleProvider lifecycle) { //showLog(request); Observable observable; //隨生命週期自動管理.eg:onCreate(start)->onStop(end) observable =apiObservable .map(new ServerResultFunction()) .compose(lifecycle.bindToLifecycle())//須要在這個位置添加 .onErrorResumeNext(new HttpResultFunction<>()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); return observable; } }

HttpRxObservable咱們構建一個被訂閱者Observable而且設置了錯誤處理,同時添加了生命週期管理。

處理訂閱者Observer

/** * 適用Retrofit網絡請求Observer(監聽者) * 備註: * 1.重寫onSubscribe,添加請求標識 * 2.重寫onError,封裝錯誤/異常處理,移除請求 * 3.重寫onNext,移除請求 * 4.重寫cancel,取消請求 * * @author ZhongDaFeng */ public abstract class HttpRxObserver<T> implements Observer<T>, HttpRequestListener { private String mTag;//請求標識 public HttpRxObserver() { } public HttpRxObserver(String tag) { this.mTag = tag; } @Override public void onError(Throwable e) { RxActionManagerImpl.getInstance().remove(mTag); if (e instanceof ApiException) { onError((ApiException) e); } else { onError(new ApiException(e, ExceptionEngine.UN_KNOWN_ERROR)); } } @Override public void onComplete() { } @Override public void onNext(@NonNull T t) { if (!TextUtils.isEmpty(mTag)) { RxActionManagerImpl.getInstance().remove(mTag); } onSuccess(t); } @Override public void onSubscribe(@NonNull Disposable d) { if (!TextUtils.isEmpty(mTag)) { RxActionManagerImpl.getInstance().add(mTag, d); } onStart(d); } @Override public void cancel() { if (!TextUtils.isEmpty(mTag)) { RxActionManagerImpl.getInstance().cancel(mTag); } } /** * 是否已經處理 * * @author ZhongDaFeng */ public boolean isDisposed() { if (TextUtils.isEmpty(mTag)) { return true; } return RxActionManagerImpl.getInstance().isDisposed(mTag); } protected abstract void onStart(Disposable d); /** * 錯誤/異常回調 * * @author ZhongDaFeng */ protected abstract void onError(ApiException e); /** * 成功回調 * * @author ZhongDaFeng */ protected abstract void onSuccess(T response); }

使用網絡請求的過程當中咱們確定會遇到取消請求的場景,這裏咱們實現一個HttpRequestListener,爲每個請求添加惟一的TAG用來標識具體的每個請求,開始請求時保存TAG,請求成功/失敗移除標誌,同時TAG也用作取消請求的標誌。

編寫一個測試類,示例如何使用Retrofit

/** * Retrofit使用demo/測試類 * * @author ZhongDaFeng */ public class RetrofitTest { public final String TAG = RetrofitTest.class.getSimpleName();//每一個網絡請求惟一TAG,用於取消網絡請求使用 /** * 模擬在activity中調用 * * @author ZhongDaFeng */ public void test(RxActivity activity, String account, String psw) { //設置惟一TAG HttpRxObserver httpRxObserver = new HttpRxObserver(TAG + "login") { @Override protected void onStart(Disposable d) { /** * 開啓loading等 */ } @Override protected void onError(ApiException e) { /** * 錯誤信息 */ LogUtils.w("onError code:" + e.getCode() + " msg:" + e.getMsg()); } @Override protected void onSuccess(Object response) { /** * 成功處理 */ LogUtils.w("onSuccess response:" + response.toString()); } }; new RetrofitTest().login(activity, account, psw).subscribe(httpRxObserver); //取消請求 /*if(!httpRxObserver.isDisposed()){ httpRxObserver.cancel(); }*/ } /** * 登陸demo * * @author ZhongDaFeng */ public Observable login(RxActivity activity, String phone, String psw) { //構建請求數據 Map<String, Object> request = HttpRequest.getRequest(); request.put("phone", phone); request.put("psw", psw); /** * 獲取請求Observable * 1.RxActivity,RxFragment...所在頁面繼承RxLifecycle支持的組件 * 2.ActivityEvent指定監聽函數解綁的生命週期(手動管理,未設置則自動管理) * 以上兩點做用防止RxJava監聽沒解除致使內存泄漏,ActivityEvent若未指定則按照activity/fragment的生命週期 */ // return HttpRxObservable.getObservable(ApiUtils.getPhoneApi().phoneQuery(request), activity); return HttpRxObservable.getObservable(ApiUtils.getUserApi().login(request), activity, ActivityEvent.PAUSE); } }

使用RxLifecycle 管理訂閱生命週期activity須要繼承RxActivity。開篇也提到MVP的時候,接下來就說說在MVP中如何使用。 
定義一個Presenter基類

public class BasePresenter<V, T> implements LifeCycleListener { protected Reference<V> mViewRef; protected V mView; protected Reference<T> mActivityRef; protected T mActivity; public BasePresenter(V view, T activity) { attachView(view); attachActivity(activity); setListener(activity); } /** * 設置生命週期監聽 * * @author ZhongDaFeng */ private void setListener(T activity) { if (getActivity() != null) { if (activity instanceof BaseActivity) { ((BaseActivity) getActivity()).setOnLifeCycleListener(this); } else if (activity instanceof BaseFragmentActivity) { ((BaseFragmentActivity) getActivity()).setOnLifeCycleListener(this); } } } /** * 關聯 * * @param view */ private void attachView(V view) { mViewRef = new WeakReference<V>(view); mView = mViewRef.get(); } /** * 關聯 * * @param activity */ private void attachActivity(T activity) { mActivityRef = new WeakReference<T>(activity); mActivity = mActivityRef.get(); } /** * 銷燬 */ private void detachView() { if (isViewAttached()) { mViewRef.clear(); mViewRef = null; } } /** * 銷燬 */ private void detachActivity() { if (isActivityAttached()) { mActivityRef.clear(); mActivityRef = null; } } /** * 獲取 * * @return */ public V getView() { if (mViewRef == null) { return null; } return mViewRef.get(); } /** * 獲取 * * @return */ public T getActivity() { if (mActivityRef == null) { return null; } return mActivityRef.get(); } /** * 是否已經關聯 * * @return */ public boolean isViewAttached() { return mViewRef != null && mViewRef.get() != null; } /** * 是否已經關聯 * * @return */ public boolean isActivityAttached() { return mActivityRef != null && mActivityRef.get() != null; } @Override public void onCreate(Bundle savedInstanceState) { } @Override public void onStart() { } @Override public void onRestart() { } @Override public void onResume() { } @Override public void onPause() { } @Override public void onStop() { } @Override public void onDestroy() { detachView(); detachActivity(); } }

JAVA弱引用,管理View的引用,以及activity的引用,避免強引用致使資源沒法釋放而形成的內存溢出, 
寫代碼的時候想到了一個很巧妙的方式:Presenter中傳如一個activity,同時實現Activity生命週期監聽,在onDestroy中移除View和Activity的引用,我的以爲這個很是不錯。看官能夠客觀評價一下優劣。

登陸Presenter

public class LoginPresenter extends BasePresenter<ILoginView, LoginActivity> { private final String TAG = PhoneAddressPresenter.class.getSimpleName(); public LoginPresenter(ILoginView view, LoginActivity activity) { super(view, activity); } /** * 登陸 * * @author ZhongDaFeng */ public void login(String userName, String password) { //構建請求數據 Map<String, Object> request = HttpRequest.getRequest(); request.put("username", userName); request.put("password", password); HttpRxObserver httpRxObserver = new HttpRxObserver(TAG + "getInfo") { @Override protected void onStart(Disposable d) { if (getView() != null) getView().showLoading(); } @Override protected void onError(ApiException e) { LogUtils.w("onError code:" + e.getCode() + " msg:" + e.getMsg()); if (getView() != null) { getView().closeLoading(); getView().showToast(e.getMsg()); } } @Override protected void onSuccess(Object response) { LogUtils.w("onSuccess response:" + response.toString()); UserBean bean = new Gson().fromJson(response.toString(), UserBean.class); if (getView() != null) { getView().closeLoading(); getView().showResult(bean); } } }; /** * 切入後臺移除RxJava監聽 * ActivityEvent.PAUSE(FragmentEvent.PAUSE) * 手動管理移除RxJava監聽,若是不設置此參數默認自動管理移除RxJava監聽(onCrete建立,onDestroy移除) */ HttpRxObservable.getObservable(ApiUtils.getUserApi().login(request), getActivity(), ActivityEvent.PAUSE).subscribe(httpRxObserver); /** * ******此處代碼爲了測試取消請求,不是規範代碼***** */ /*try { Thread.sleep(50); //取消請求 if (!httpRxObserver.isDisposed()) { httpRxObserver.cancel(); } } catch (InterruptedException e) { e.printStackTrace(); }*/ } }

LoginActivity

public class LoginActivity extends BaseActivity implements ILoginView { @BindView(R.id.et_user_name) EditText etUserName; @BindView(R.id.et_password) EditText etPassword; private LoginPresenter mLoginPresenter = new LoginPresenter(this, this); private RLoadingDialog mLoadingDialog; @Override protected int getContentViewId() { return R.layout.activity_login; } @Override protected void init() { mLoadingDialog = new RLoadingDialog(this, true); } @Override protected void initBundleData() { } @OnClick({R.id.login}) public void onClick(View v) { switch (v.getId()) { case R.id.login: String userName = etUserName.getText().toString(); String password = etPassword.getText().toString(); if (TextUtils.isEmpty(userName) || TextUtils.isEmpty(password)) { return; } mLoginPresenter.login(userName, password); break; } } @Override public void showResult(UserBean bean) { if (bean == null) { return; } showToast(bean.getUid()); } @Override public void showLoading() { mLoadingDialog.show(); } @Override public void closeLoading() { mLoadingDialog.dismiss(); } @Override public void showToast(String msg) { ToastUtils.showToast(mContext, msg); } }

以上是我對MVP的一點理解,以及對RxJava2+Retrofit2+RxLifecycle2進行的封裝,因爲編寫demo的時候是朝着構建一個項目框架走的,因此沒有貼完的代碼就請移步到個人Github克隆完整版本,盡情的擼吧。 
我的認爲這個搭配仍是可行的,而且已經投入都項目中。

GitHub:https://github.com/RuffianZhong/Rx-Mvp

相關文章
相關標籤/搜索