RxJava2 + Retrofit2 優雅簡潔封裝

database 7年前發布 | 44K 次閱讀 RxJava Retrofit Java開發

RxJava2 封裝主要變化

  • Transformer的變化:RxJava1.X為rx.Observable.Transformer接口, 繼承自Func1<Observable<T>, Observable<R>>, RxJava2.X為io.reactivex.ObservableTransformer<Upstream, Downstream>,是一個獨立的接口。
  • Flowable則是FlowableTransformer,如果你使用Flowable,以下ObservableTransformer替換FlowableTransformer即可。

RxJava2 + Retrofit2.jpg

封裝方案

1、封裝 Rx 線程相關

RxSchedulersHelper:

/**

  • Created by weiss on 17/1/16. */ public class RxSchedulers { public static <T> ObservableTransformer<T, T> io_main() {
     return upstream ->
             upstream.subscribeOn(Schedulers.io())
             .observeOn(AndroidSchedulers.mainThread());
    
    } }</code></pre>

    封裝后:

    Api.getInstance().movieService
    
             .getGankData("Android",1)
             .compose(RxSchedulers.io_main());</code></pre> 
    

    2、封裝 處理服務器返回數據,管理 RxJava生命周期

    HttpResult:

    /**
  • Created by Weiss on 2017/1/11. */

public class HttpResult<T> implements Serializable { public String code; public String msg; public boolean hasmore; public T data;

public static String SUCCESS = "000";
public static String SIGN_OUT = "101";//token驗證失敗
public static String SHOWTOAST = "102";//顯示Toast

public boolean isSuccess() {
    return SUCCESS.equals(code);
}

public boolean isTokenInvalid() {
    return SIGN_OUT.equals(code);
}

public boolean isShowToast() {
    return SHOWTOAST.equals(code);
}

public boolean hasMore() {
    return hasmore;
}

}</code></pre>

BaseRxActivity:

/**

  • 管理RxJava生命周期,避免內存泄漏
  • RxJava處理服務器返回 *
  • Created by Weiss on 2016/12/23. */

public abstract class BaseRxActivity extends BaseActivity {

private CompositeDisposable disposables2Stop;// 管理Stop取消訂閱者者
private CompositeDisposable disposables2Destroy;// 管理Destroy取消訂閱者者

protected abstract int getLayoutId();

protected abstract void initView();

/**
 * Rx優雅處理服務器返回
 *
 * @param <T>
 * @return
 */
public <T> ObservableTransformer<HttpResult<T>, T> handleResult() {
    return upstream ->{
            return upstream.flatMap(result -> {
                        if (result.isSuccess()) {
                            return createData(result.data);
                        } else if (result.isTokenInvalid()) {
                            //處理token失效,tokenInvalid方法在BaseActivity 實現
                             tokenInvalid();
                        } else {
                            return Observable.error(new Exception(result.msg));
                        }
                        return Observable.empty();
                    }

            );
    };
}

private <T> Observable<T> createData(final T t) {
    return Observable.create(subscriber -> {
        try {
            subscriber.onNext(t);
            subscriber.onComplete();
        } catch (Exception e) {
            subscriber.onError(e);
        }
    });
}

public boolean addRxStop(Disposable disposable) {
    if (disposables2Stop == null) {
        throw new IllegalStateException(
                "addUtilStop should be called between onStart and onStop");
    }
    disposables2Stop.add(disposable);
    return true;
}

public boolean addRxDestroy(Disposable disposable) {
    if (disposables2Destroy == null) {
        throw new IllegalStateException(
                "addUtilDestroy should be called between onCreate and onDestroy");
    }
    disposables2Destroy.add(disposable);
    return true;
}

public void remove(Disposable disposable) {
    if (disposables2Stop == null && disposables2Destroy == null) {
        throw new IllegalStateException("remove should not be called after onDestroy");
    }
    if (disposables2Stop != null) {
        disposables2Stop.remove(disposable);
    }
    if (disposables2Destroy != null) {
        disposables2Destroy.remove(disposable);
    }
}

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (disposables2Destroy != null) {
        throw new IllegalStateException("onCreate called multiple times");
    }
    disposables2Destroy = new CompositeDisposable();
}

public void onStart() {
    super.onStart();
    if (disposables2Stop != null) {
        throw new IllegalStateException("onStart called multiple times");
    }
    disposables2Stop = new CompositeDisposable();
}

public void onStop() {
    super.onStop();
    if (disposables2Stop == null) {
        throw new IllegalStateException("onStop called multiple times or onStart not called");
    }
    disposables2Stop.dispose();
    disposables2Stop = null;
}

public void onDestroy() {
    super.onDestroy();
    if (disposables2Destroy == null) {
        throw new IllegalStateException(
                "onDestroy called multiple times or onCreate not called");
    }
    disposables2Destroy.dispose();
    disposables2Destroy = null;
}

}</code></pre>

封裝后 (BaseRxActivity的子類使用):

addRxDestroy(Api.getInstance().movieService
                .getGankData("Android",1)
                .compose(RxSchedulers.io_main())
                .compose(handleResult())
                .省略
);

handleResult為什么不新建一個類處理呢?因為很多異常處理需要context對象,或者和BaseActivity有千絲萬縷的聯系,BaseRxActivity繼承BaseActivity可以很簡潔優雅處理各種異常。比如token失效,是需要跳轉到登錄頁面的。在新建一個類中,不能持有context對象,只能使用Application的Context,同時方便與Activity通信交互滿足各種需求。BaseRxActivity還可以管理RxJava生命周期。

3、異常處理

/**

  • Created by Weiss on 2017/2/9. */

public class RxException<T extends Throwable> implements Consumer<T> {

private static final String TAG = "RxException";

private static final String SOCKETTIMEOUTEXCEPTION = "網絡連接超時,請檢查您的網絡狀態,稍后重試";
private static final String CONNECTEXCEPTION = "網絡連接異常,請檢查您的網絡狀態";
private static final String UNKNOWNHOSTEXCEPTION = "網絡異常,請檢查您的網絡狀態";

private Consumer<? super Throwable> onError;
public RxException(Consumer<? super Throwable> onError) {
    this.onError=onError;
}

/**
 * Consume the given value.
 *
 * @param t the value
 * @throws Exception on error
 */
@Override
public void accept(T t) throws Exception {
    if (t instanceof SocketTimeoutException) {
        Log.e(TAG, "onError: SocketTimeoutException----" + SOCKETTIMEOUTEXCEPTION);
        ToastUtils.show(SOCKETTIMEOUTEXCEPTION);
        onError.accept(new Throwable(SOCKETTIMEOUTEXCEPTION));
    } else if (t instanceof ConnectException) {
        Log.e(TAG, "onError: ConnectException-----" + CONNECTEXCEPTION);
        ToastUtils.show(CONNECTEXCEPTION);
        onError.accept(new Throwable(CONNECTEXCEPTION));
    } else if (t instanceof UnknownHostException) {
        Log.e(TAG, "onError: UnknownHostException-----" + UNKNOWNHOSTEXCEPTION);
        ToastUtils.show(UNKNOWNHOSTEXCEPTION);
        onError.accept(new Throwable(UNKNOWNHOSTEXCEPTION));
    } else {
        Log.e(TAG, "onError:----" + t.getMessage());
        onError.accept(t);
    }
}

}</code></pre>

封裝后 (BaseRxActivity的子類使用):

addRxDestroy(Api.getInstance().movieService
                .getGankData("Android",1)
                .compose(RxSchedulers.io_main())
                .compose(handleResult())
                .subscribe(httpResult -> adapter.setItems(httpResult.data),
                                new RxException<>(e ->e.printStackTrace()))
);

4、多頁請求封裝

實體類:

/**

  • Created by Weiss on 2017/1/20. */

public class Gank extends BaseListEntity { @Override public Flowable<HttpResult<List<Gank>>> getPage(int page) { return GankApi.getInstance().service.getGankData(param.get("gank"), page) .compose(RxSchedulers.io_main()); }

}</code></pre>

實體類繼承 BaseListEntity,實現getPage方法即可。

UI視圖:

public class MainActivityFragment extends BaseRxFragment {
    @BindView(R.id.baseRecyclerView)
    PtrRecyclerView ptrRecyclerView;

private MultiTypeAdapter adapter;

public MainActivityFragment() {
}


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

@Override
protected void initView() {
    ptrRecyclerView.setParam("gank","Android");
    adapter = new MultiTypeAdapter();
    adapter.register(Gank.class,new GankViewProvider());
    ptrRecyclerView.setAdapter(adapter,new Gank());
}

}</code></pre>

只需要寫一個適配器和實體類,輕松實現多頁請求,PtrRecyclerView下拉刷新和上拉加載自動獲取數據。

PtrRecyclerView目前只是簡單實現下拉刷新和上拉加載,有空會完善,當然例子也會完善。

后記

還可以封裝網絡加載對話框,這個看個人喜好,同樣以上封裝同樣可以看個人喜好和項目需求自由組裝。

 

 

來自:http://www.jianshu.com/p/4005bc4a20f2

 

 本文由用戶 database 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!