Android 我的Retrofit+Rxjava封裝,不搞花里胡俏

前言

從我最開始用rx和retrofit.到現(xiàn)在,快3年了.

這個庫的內(nèi)容,算是沉淀下來的東西.

個人用這個做過的項目也有很多個了.和項目中用的有點區(qū)別.

因為不能隨便重構(gòu)的原因,比項目里的更好.哈哈.

目錄:

image

初始化:

NetWorkManager.init(String baseUrl, Application context)

難點1 BaseBean:

作為一個庫,這個類是一個頭疼的問題.因為強耦合.

我們一般寫的baseBaen都是這樣的:

class BaseBean<T>{
  String code;
  T data;
  String msg;
}

不同的人,有不同的協(xié)議,字段名會不一樣,如果用這樣的,明顯是不行的.

這個庫是這樣的(ParseInfo):

你只需要定義自己的basebean規(guī)則,即可

image

例子

 NetWorkManager.addParseInfo(
                new RxParseInfo("code", "data", "msg", "200") //200代表成功時的code.
        );

這里傳入的參數(shù)都是key的名字.

目前支持3個key值.我覺得基本夠用了.

codeKey判斷成功

dataKey返回數(shù)據(jù)

msgKey服務(wù)器返回消息

庫是如何判斷接口請求成功的

ParseInfo 里默認通過判斷successCode與返回的codeKey的值進行比較的

 public boolean isSuccess(JsonObject asJsonObject) {
        if (checkSuccess != null) {
            return checkSuccess.isSuccess(asJsonObject);
        }
        String code = asJsonObject.get(codeKey).toString();
        return TextUtils.equals(code, successCode);
    }

也可以自定義判斷是否請求成功

ParseInfo使用setCheckSuccess().非必須.主要是為了擴展.

new ParseInfo("code", "data", "msg", "200")
 .setCheckSuccess(new ParseInfo.CheckSuccess() {
                    @Override
                    public boolean isSuccess(JsonObject asJsonObject) {
                        return false;
                    }
                })

請求:

public interface JApi {

    /**
     * 上傳文件
      */
    @POST
    @Multipart
    Observable<String> post(@Url String url, @PartMap HashMap<String, RequestBody> params);

    /**
     * 通用POST
     *
     */
    @POST
    Observable<String> post(@Url String url, @Body String json);

    /**
     * 通用POST
     */
    @POST
    Observable<String> post(@Url String url, @Body SimpleParams json);

    /**
     * 通用get
     */
    @GET
    Observable<String> get(@Url String url, @QueryMap SimpleParams params);

}

這里寫了4個通用的retrofit的請求.我個人覺得是可以滿足大部分的需求了.

如果滿足不了.就寫點定制的就好了.有人會覺得這么寫不行,實際上,我就用這個已經(jīng)寫了很多項目了.

有人會問,為什么這里都是Observable<String>,往后面看就知道了.嘿嘿

RetrofitUtil

這里使用了餓漢式懶加載單例.

public class RetrofitUtil {
    /**
     * 服務(wù)器地址
     */
    private static String API_HOST;
    private static Application mContext;
    private static final HashMap<Class, Object> apis = new HashMap<>();

    @SuppressWarnings("unchecked")
    public static <T> T getApi(Class<T> c) {
        Object o = apis.get(c);
        if (null == o) {
            o = getInstance().create(c);
            apis.put(c, o);
        }
        return (T) o;
    }

    public static synchronized void init(String baseUrl, Application context) {
        if (TextUtils.isEmpty(baseUrl)) {
            return;
        }
        mContext = context;
        API_HOST = baseUrl;
        Instance.retrofit = Instance.getRetrofit();
        apis.clear();
    }

    public static Retrofit getInstance() {
        return Instance.retrofit;
    }

    private static class Instance {
        private static Retrofit retrofit = getRetrofit();

        private static Retrofit getRetrofit() {
            OkHttpClient.Builder client = new OkHttpClient.Builder()
                    //攔截并設(shè)置緩存
                    .addNetworkInterceptor(new CacheInterceptor())
                    //攔截并設(shè)置緩存
                    .addInterceptor(new CacheInterceptor())
                    .cache(new Cache(mContext.getCacheDir(), 10240 * 1024));
            // 設(shè)置代理
            if (NetWorkManager.getProxy() != null) {
                client.proxy(NetWorkManager.getProxy());
            }

            for (Interceptor i : NetWorkManager.mInterceptors) {
                client.addInterceptor(i);
            }
            if (BuildConfig.DEBUG) {
                HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
                interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
                client.addInterceptor(interceptor);
            }
            return new Retrofit.Builder()
                    .client(client.build())
                    .baseUrl(API_HOST)
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .build();
        }
    }

可以設(shè)置緩存,添加代理,重置baseurl

對Retrofit.create創(chuàng)建的實體類,進行了緩存.

看了半天,先來個例子吧:

Disposable login = RetrofitUtil.getApi(JApi.class)
                .get("/login", SimpleParams.create()
                        .putP("key1", 1)
                        .putP("key2", 2)
                        .putP("key3", 2)
                        .putP("key4", 3)
                )
                .compose(JRxCompose.normal())
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {

                    }
                });

一個簡單的請求就是這樣的.

有人看了會問, JRxCompose是啥?

JRxCompose

先來張目錄圖

image

再來張代碼

image

這里為什么要寫JsonArrayParesTransformerJsonParesTransformer.

因為在組件化的時候,跨組件GSON解析時,泛型是會丟失的.我不知道現(xiàn)在解決沒.

所以使用這兩個來統(tǒng)一解析結(jié)果.

如果你細心就會發(fā)現(xiàn).JApi的方法,的返回參數(shù)都是Observable<String>

也就是統(tǒng)一先用String接收結(jié)果,然后再解析成最終結(jié)果.


看到這里,你滿足了嗎? 我是不滿足的.哈哈

難點2 取消網(wǎng)絡(luò)請求

如何舒服的取消請求回調(diào)一直是個頭疼的問題

不取消就會內(nèi)存泄露,調(diào)用已關(guān)閉的activity,造成崩潰.

當(dāng)然,現(xiàn)在有RxLifecyle之類的庫,很方便.

這里我簡單實現(xiàn)了一個.不過有版本限制.依賴Android自帶的Lifecycle

JApiImpl

public class JApiImpl implements JApi, LifecycleObserver, ObservableTransformer<String, String> {

    public static JApi getApi() {
        return RetrofitUtil.getApi(JApi.class);
    }

    public static JApiImpl with(Lifecycle lifecycle) {
        JApiImpl JApiImpl = new JApiImpl();
        lifecycle.addObserver(JApiImpl);
        return JApiImpl;
    }

    public static JApiImpl with(Fragment fragment) {
        return with(fragment.getLifecycle());
    }

    public static JApiImpl with(AppCompatActivity activity) {
        return with(activity.getLifecycle());
    }

    private Disposable disposable;

    @Override
    public ObservableSource<String> apply(Observable<String> upstream) {
        return upstream.doOnSubscribe(disposable -> this.disposable = disposable);
    }

    private void cancel() {
        if (this.disposable != null && !disposable.isDisposed()) {
            disposable.dispose();
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public void onDestroy() {
        this.cancel();
        Log.i("233", "取消了請求");
    }

    @Override
    public Observable<String> post(String url, HashMap<String, RequestBody> params) {
        return getApi().post(url, params).compose(this);
    }

    @Override
    public Observable<String> post(String url, String json) {
        return getApi().post(url, json).compose(this);
    }

    @Override
    public Observable<String> post(String url, SimpleParams params) {
        return getApi().post(url, params).compose(this);
    }

    @Override
    public Observable<String> get(String url, SimpleParams params) {
        return getApi().post(url, params).compose(this);
    }

}

實現(xiàn)了JApi,LifecycleObserver,ObservableTransformer

LifecycleObserver是為了利用現(xiàn)在android自帶的Lifecycle實現(xiàn)取消回調(diào)

ObservableTransformer是為了轉(zhuǎn)換Observer.拿到Disposable.

這么改一下后.請求就可以這樣:

            JApiImpl.with(this)
                .get("/login", SimpleParams.create()
                        .putP("key1", 1)
                        .putP("key2", 2)
                        .putP("key3", 2)
                        .putP("key4", 3)
                )
                .compose(JRxCompose.normal())
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {

                    }
                });

添加加密/解密

        NetWorkManager.initKey("私鑰", "公鑰");//加密解密

設(shè)置超時時間

        NetWorkManager.setDefaultTimeOut(20);//秒

設(shè)置重試次數(shù)

        NetWorkManager.setDefaultRetry(5);//重試次數(shù)

設(shè)置全局異常統(tǒng)一回調(diào)

   NetWorkManager.setExceptionListener(new onExceptionListener() {
            @Override
            public String onError(Throwable throwable) {
                return null; 
            }
        });

設(shè)置添加全局code狀態(tài)處理

  NetWorkManager.setApiCallBack(new APICallBack() {
            @Override
            public String callback(String code, String resultData) {
                JsonElement jsonElement = JSONFactory.parseJson(resultData);
                return JSONFactory.getValue(jsonElement, "message");
            }
        });

設(shè)置打開服務(wù)器返回msg異常

如果callback不處理,并打開isOpenApiException,則拋出服務(wù)器返回msg信息

NetWorkManager.setOpenApiException(true);

異常的處理邏輯

    String errorMsg = null;
    //通過code獲取注冊的接口回調(diào).
    APICallBack apiCallback = NetWorkManager.getApiCallback();
    if (apiCallback != null) {
        String callbackMsg = apiCallback.callback(code, response);
        if (!TextUtils.isEmpty(callbackMsg)) {
            errorMsg = callbackMsg;
        }
    }

    //如果callback不處理,并打開isOpenApiException,則拋出服務(wù)器返回msg信息
    if (TextUtils.isEmpty(errorMsg) && NetWorkManager.isOpenApiException()) {
        errorMsg = msg;
    }
    //拋出異常,走到onError.
    throw new APIException(code, errorMsg);

解析結(jié)果是Object或Array的例子:

        //結(jié)果是一個Object
        JApiImpl.with(this)
                .post("/Login", SimpleParams.create())
                .compose(JRxCompose.obj(Login.class))
                .subscribe(new Consumer<Login>() {
                    @Override
                    public void accept(Login login) throws Exception {

                    }
                });
        //結(jié)果是集合
        JApiImpl.with(this)
                .post("/Login", SimpleParams.create())
                .compose(JRxCompose.array(Login.class))
                .subscribe(new Consumer<List<Login>>() {
                    @Override
                    public void accept(List<Login> logins) throws Exception {
                        
                    }
                });

簡單的Observer

這里支持傳入CompositeDisposable,添加當(dāng)前的Disposable,用于取消回調(diào),如果你用了上面的
JApiImpl,那么這里可以不傳CompositeDisposable,這個是我最早實現(xiàn)統(tǒng)一取消回調(diào)的邏輯.

/**
 * @author jlanglang  2016/11/14 17:32
 * @版本 2.0
 * @Change
 */
public abstract class SimpleObserver<T> implements Observer<T> {
    protected Disposable mDisposable;
    private CompositeDisposable mCompositeDisposable;

    public SimpleObserver() {
        this(null);
    }

    public SimpleObserver(CompositeDisposable compositeDisposable) {
        mCompositeDisposable = compositeDisposable;
    }

    @Override
    public void onSubscribe(@NonNull Disposable d) {
        mDisposable = d;
        try {
            mCompositeDisposable.add(d);
        } catch (Exception ignored) {

        }
    }

    @Override
    public void onNext(T t) {
        call(t);
    }

    @Override
    public void onError(Throwable e) {
     
    }


    @Override
    public void onComplete() {

    }

    public abstract void call(@NonNull T t);
}

ToastObserver

在實際使用的時候,我們一般不會每個請求都彈Toast.
所以.如果需要默認彈Toast的請求.可以使用這個類.

/**
 * @author jlanglang  2016/11/14 17:32
 */
public abstract class ToastObserver<T> extends SimpleObserver<T> {

    public ToastObserver() {
        this(null);
    }

    public ToastObserver(CompositeDisposable com) {
        super(com);
    }

    @Override
    public void onError(Throwable e) {
        String errorMsg = NetWorkErrorFactory.disposeError(e);
        if (!TextUtils.isEmpty(errorMsg)) {
            Toast.makeText(NetWorkManager.getContext(), errorMsg, Toast.LENGTH_SHORT).show();
        }
    }
}

異常解析工廠

這個類,其實讓我很糾結(jié),因為這個類好像沒什么作用.又好像又作用.
但是太繞了.
比如在NetWorkTransformer中拋出的APIException,以及初始化設(shè)置的onExceptionListener
都是這里來處理的.
但不調(diào)用這個方法.這個方法就無意義.

我是在上面的ToastObserver中調(diào)用了這個方法.
你可以自定義這個方法在哪調(diào)用.

 /**
     * 異常時處理工廠
     *
     * @param throwable 異常
     * @return 獲取異常提示消息
     */
    public static String disposeError(Throwable throwable) {
        Class<? extends Throwable> throwableClass = throwable.getClass();
        //處理Api自定義異常處理,請求是成功的,如果需要特殊處理,使用APICallBack
        if (throwableClass.equals(APIException.class)) {
            return throwable.getMessage();
        }
        //處理error異常,http異常
        onExceptionListener exceptionListener = NetWorkManager.getExceptionListener();
        if (exceptionListener != null) {
            return exceptionListener.onError(throwable);
        }
        return "";
    }

結(jié)語

大致使用就這些了.

庫里還包含了rxbus.

歡迎大家點贊,留言提建議

github地址: JRxRetrofit

交流群:

Flutter:782978118

Android:493180098

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖鸠姨,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡谤职,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門亿鲜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來允蜈,“玉大人,你說我怎么就攤上這事蒿柳∪奶祝” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵垒探,是天一觀的道長妓蛮。 經(jīng)常有香客問我,道長圾叼,這世上最難降的妖魔是什么蛤克? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮夷蚊,結(jié)果婚禮上构挤,老公的妹妹穿的比我還像新娘。我一直安慰自己撬码,他們只是感情好儿倒,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著呜笑,像睡著了一般夫否。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上叫胁,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天凰慈,我揣著相機與錄音,去河邊找鬼驼鹅。 笑死微谓,一個胖子當(dāng)著我的面吹牛森篷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播豺型,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼仲智,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了姻氨?” 一聲冷哼從身側(cè)響起钓辆,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肴焊,沒想到半個月后前联,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡娶眷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年似嗤,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片届宠。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡烁落,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出席揽,到底是詐尸還是另有隱情顽馋,我是刑警寧澤谓厘,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布幌羞,位于F島的核電站,受9級特大地震影響竟稳,放射性物質(zhì)發(fā)生泄漏属桦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一他爸、第九天 我趴在偏房一處隱蔽的房頂上張望聂宾。 院中可真熱鬧,春花似錦诊笤、人聲如沸系谐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纪他。三九已至,卻和暖如春晾匠,著一層夾襖步出監(jiān)牢的瞬間茶袒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工凉馆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留薪寓,地道東北人亡资。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像向叉,于是被迫代替她去往敵國和親锥腻。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

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