Retrofit2.0結合RxAndroid實現二次封裝

    實Retrofit2.0結合RxAndroid現網絡請求網上有不少文章,這裏再也不詳細介紹服務器

    Retrofit基本是一個業務請求,對應一個接口方法,由於其返回值不支持泛型,只能是具體的類。好處是結構清楚,缺點是業務請求就耦合的網絡接口,若是之後想分離網絡就很麻煩。並且開發人員還要同時定義每一個業務的請求接口,和具體的請求方式,對於大型APP,工做量很大,並且容易出錯。網絡

    本文主要介紹如何對Retrofit2.0+RxAndroid封裝成網絡層,對業務使用隔離,使用者不須要知道網絡框架使用的是哪一種技術,只須要使用通用的接口,便可實現不一樣業務請求的調用。框架

    下面這種泛型返回類型,Retrofit在運行是會報錯,啃爹啊。ide

@GET(ACTION_URL)
<T extends BaseResult> Observable<T> requestNetwokData(@Query("a") String type, @QueryMap Map<String, String> options);

    下面是變相的實現方式,基本技術不變,只是在服務器返回數據時作了一個簡單的處理。post

    1. 返回的數據使用OKHttp原始的類型ResponseBodythis

    2. 數據返回後,經過RxAndroid的map方法,強制根據調用者要求的類型進行轉換spa

@GET(ACTION_URL)
Observable<ResponseBody> requestNetwokData(@Query("a") String type, @QueryMap Map<String, String> options);
public void startRequest(ServiceMap serviceMap, Map<String, String> paramMap) {
    NetworkResult networkResult = new NetworkResult();
    networkResult.mServiceMap = serviceMap;
    Observable<ResponseBody> observable = mHttpApi.requestNetwokData(serviceMap.getmServiceType(), paramMap);
    subscribeOn(networkResult, observable);
}
private void subscribeOn(final NetworkResult networkResult, final Observable<ResponseBody> observable) {
    Subscription subscription = observable.subscribeOn(Schedulers.io())
            // subscribe()調用後並且在事件發送前執行
            // 默認狀況下,doOnSubscribe()執行在subscribe()發生的線程
            // 若是在doOnSubscribe()以後有subscribeOn()的話,它將執行在離它最近的subscribeOn()所指定的線程
            .doOnSubscribe(new Action0() {
                @Override
                public void call() {
                    postNetSubscribe(SubscribeNetwork.TAG_NET_ONSTART, networkResult);
                }
            }).subscribeOn(AndroidSchedulers.mainThread())
            .map(new Func1<ResponseBody, BaseResult>() {
                @Override
                public BaseResult call(ResponseBody resBody) {
                    NLog.e("retrofit", "map thread " + Thread.currentThread());
                    try {
                        return JSON.parseObject(resBody.bytes(), networkResult.mServiceMap.getmClazz());
                    } catch (IOException e) {
                        e.printStackTrace();
                        return null;
                    }
                }
            })
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Subscriber<BaseResult>() {
                @Override
                public void onCompleted() {
                    postNetSubscribe(SubscribeNetwork.TAG_NET_ONCOMPLETED, networkResult);
                }

                @Override
                public void onError(Throwable e) {
                    postNetSubscribe(SubscribeNetwork.TAG_NET_ONERROR, networkResult);
                }

                @Override
                public void onNext(BaseResult baseResult) {
                    NLog.e("retrofit", "onNext thread " + Thread.currentThread());
                    networkResult.mResponseResult = baseResult;
                    postNetSubscribe(SubscribeNetwork.TAG_NET_ONRESULT, networkResult);
                }
            });
    // add方法內作了線程同步功能
    mCompositeSubscription.add(subscription);
}

    上面就是本人的變相處理方式,哪位大神有好的方法,歡迎指導。.net

 

    RxBus post方法遇到的坑線程

    1. 使用post方法通知訂閱者,網絡數據返回code

/**
 * 給訂閱者髮網絡處理消息
 * @param tag
 * @param networkResult
 */
private void postNetSubscribe(String tag, @NonNull NetworkResult networkResult) {
    if (networkResult.mResponseResult == null) {
        // 保證mResponseResult永遠都不爲null
        networkResult.mResponseResult = new BaseResult();
    }
    RxBus.get().post(tag, networkResult);
}

    2. 通用的訂閱者,接收網絡數據返回,再分發給不一樣界面

public class SubscribeNetwork {
    private INetworkListener networkListener;
    public SubscribeNetwork(INetworkListener listener) {
        this.networkListener = listener;
    }
    public void register() {
        // 網絡請求處理結果監聽
        RxBus.get().register(this);
    }
    
    public void unregister() {
        // 解除網絡處理結果監聽
        RxBus.get().unregister(this);
    }
    
    @Subscribe(tags = {@Tag(TAG_NET_ONRESULT)})
    public void subscribeNetResult(NetworkResult networkResult) {
        if (networkListener != null) {
            networkListener.onNetResult(networkResult);
        }
    }
}

    3. SubscribeNetwork的註冊,是在Fragment建立時,初始化的。

    問題:

    在使用ViewPager + Fragment時,默認會建立2個Fragment,即會註冊2個RxBus的訂閱者。

    不論第二個Fragment是否進行網絡請求,再第一個網絡請求返回時,都會調用subscribeNetResult方法,進而調用networkListener的回調。

    因此致使Fragment的網絡回調會屢次調用。

    解決:

    只能使用接口方式,進行返回,不使用rxbus的post方式。

  /**
     * 給訂閱者髮網絡處理消息
     * @param tag
     * @param networkResult
     */
    private void postNetSubscribe(String tag, @NonNull NetworkResult networkResult) {
        if (networkResult.mResponseResult == null) {
            // 保證mResponseResult永遠都不爲null
            networkResult.mResponseResult = new BaseResult();
        }
//        RxBus.get().post(tag, networkResult);
        if (mNetworkListener != null) {
            if (INetworkListener.TAG_NET_ONSTART.equals(tag)) {
                mNetworkListener.onNetStart(networkResult);
            } else if (INetworkListener.TAG_NET_ONRESULT.equals(tag)) {
                mNetworkListener.onNetResult(networkResult);
            } else if (INetworkListener.TAG_NET_ONCOMPLETED.equals(tag)) {
                mNetworkListener.onNetCompleted(networkResult);
            } else if (INetworkListener.TAG_NET_ONERROR.equals(tag)) {
                mNetworkListener.onNetError(networkResult);
            }
        }
    }
相關文章
相關標籤/搜索