Android 簡(jiǎn)單封裝 RxJava + Retrofit

如今RxJava和Retrofit的結(jié)合使用估計(jì)已經(jīng)相當(dāng)普遍了坎背,自己工作中也是一直都在使用。在使用的過(guò)程中我們都會(huì)對(duì)其進(jìn)行封裝使用寄雀,GitHub上也有很多封裝好的項(xiàng)目可以直接拿來(lái)使用,其實(shí)對(duì)于開(kāi)源框架的二次封裝有時(shí)候針對(duì)不同的業(yè)務(wù)邏輯封裝的過(guò)程中也多多少少有些不同盒犹,建議還是自己動(dòng)手去封裝使用。這樣不僅提升自己對(duì)原框架的理解阿趁,還可以提高自己的封裝能力坛猪。在工作過(guò)程中如需要改動(dòng)便更加容易入手。好了墅茉,廢話不多說(shuō),這里做了一個(gè)簡(jiǎn)單的樣本供大家參考就斤。


添加依賴(lài)


compile 'com.squareup.retrofit2:retrofit:2.3.0'

compile 'io.reactivex.rxjava2:rxjava:2.x.y'

implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'

implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'

compile 'com.squareup.retrofit2:converter-gson:2.3.0'

compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'

添加依賴(lài)本并不想多說(shuō),我想大家都知道洋机,但是對(duì)于剛接觸這些知識(shí)的時(shí)候我想有沒(méi)有人在看網(wǎng)上的文章時(shí)會(huì)覺(jué)得有些依賴(lài)是在哪找到并添加的呢?例如:com.squareup.retrofit2:converter-gson:2.3.0我們要添加一個(gè)GsonConverter的依賴(lài)绷旗。對(duì)于剛接觸這些知識(shí)和不經(jīng)常逛GitHub的人來(lái)說(shuō)會(huì)不會(huì)一臉懵逼呢?不管會(huì)不會(huì)衔肢,反正我第一次接觸的時(shí)候確實(shí)懵逼了下庄岖。這里給那些懵逼過(guò)的人提示下角骤,我們可以通過(guò)打開(kāi)GitHub上項(xiàng)目的子文件查看到相應(yīng)的依賴(lài)。比如GitHub上Retrofit項(xiàng)目中:retrofit/retrofit-converters/gson/這個(gè)路徑下就可以查看到相應(yīng)的GsonConverter的依賴(lài)。

封裝Retrofit(單例模式)


public class HttpRequest {

 public static final long CONNECTTIME = 30000;

 public static final String BASE_URL = "http://jxhdapi.ooowin.com/";

 private ApiService apiService;

 public HttpRequest() {

 //添加日志攔截器

 HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {

 @Override

 public void log(String message) {

 Log.d("TAG", "==========" + message);

 }

 }).setLevel(HttpLoggingInterceptor.Level.BODY);

 //獲取OkHttpClient

 OkHttpClient client = new OkHttpClient.Builder()

 .connectTimeout(CONNECTTIME, TimeUnit.MICROSECONDS)

 .readTimeout(CONNECTTIME,TimeUnit.MICROSECONDS)

 .writeTimeout(CONNECTTIME,TimeUnit.MICROSECONDS)

 .addInterceptor(interceptor)

 .addNetworkInterceptor(new HttpHeaderInterceptor())

 .build();

 //初始化Retrofit

 Retrofit retrofit = new Retrofit.Builder()

 .baseUrl(BASE_URL)

 .addConverterFactory(GsonConverterFactory.create())

 .addCallAdapterFactory(RxJava2CallAdapterFactory.create())

 .client(client)

 .build();

 apiService = retrofit.create(ApiService.class);

 }

 // 創(chuàng)建單例

 private static class SingletonHolder {

 private static final HttpRequest INSTANCE = new HttpRequest();

 }

 public static ApiService getApi(){

 return SingletonHolder.INSTANCE.apiService;

 }

}

這里我們可以看到添加了兩個(gè)攔截器:日志攔截器和網(wǎng)絡(luò)請(qǐng)求Header攔截器优烧,我們都知道對(duì)于Retrofit我們是可以直接通過(guò)GsonConverter轉(zhuǎn)換成實(shí)體類(lèi)的牢撼,但有的時(shí)候我們又想去獲取它的json數(shù)據(jù)進(jìn)行查看,這個(gè)時(shí)候我們就可以通過(guò)添加日志攔截器實(shí)現(xiàn)熏版,但一定要給它設(shè)置setLevel方法纷责,設(shè)置不同的屬性打印出來(lái)的數(shù)據(jù)是不一樣的撼短。至于添加Header攔截器我想大家都應(yīng)該知道,正常工作中接口所需要的Header都是相同的曲横,所以我們要進(jìn)行統(tǒng)一添加:


public class HttpHeaderInterceptor implements Interceptor {

 @Override

 public Response intercept(Chain chain) throws IOException {

 Request request = chain.request();

 Request build = request.newBuilder()

// .addHeader("","")  添加header

 .build();

 return chain.proceed(build);

 }

}

封裝實(shí)體類(lèi)


{

"code": 1,

"msg": "操作成功",

"data": {······}

}

通常我們從服務(wù)端拿到的json數(shù)據(jù)就像上面那樣,有些返回的字段內(nèi)容格式是固定的禾嫉,比如:code和msg。有些則是不確定熙参,如:data。這個(gè)時(shí)候我們就需要對(duì)其進(jìn)行二次處理了孽椰,我們可以寫(xiě)一個(gè)基類(lèi):


public class BaseBean<T> {

 private int code;

 private String msg;

 private T data;

 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;

 }

 public T getData() {

 return data;

 }

 public void setData(T data) {

 this.data = data;

 }

}

利用泛型來(lái)表示data中的不確定格式的數(shù)據(jù),這里用一個(gè)獲取全國(guó)所有省的數(shù)據(jù)接口進(jìn)行測(cè)試:


public interface ApiService {

 //獲取省列表

 @GET("common/areas")

 Flowable<BaseBean<List<Province>>> province();

}

實(shí)體類(lèi)封裝好后我們可以進(jìn)行一下測(cè)試:


HttpRequest.getApi()

 .province()

 .subscribeOn(Schedulers.io())

 .observeOn(AndroidSchedulers.mainThread())

 .subscribe(new Subscriber<BaseBean<List<Province>>>() {

 @Override

 public void onSubscribe(Subscription s) {

 }

 @Override

 public void onNext(BaseBean<List<Province>> listBaseBean) {

 }

 @Override

 public void onError(Throwable t) {

 }

 @Override

 public void onComplete() {

 }

 });

}

通過(guò)上面的代碼我們不難看出這是經(jīng)過(guò)封裝后的效果,但是我們會(huì)發(fā)現(xiàn)這樣的請(qǐng)求我們難道每次都要去添加調(diào)度器和重寫(xiě)Subscriber的幾個(gè)方法嗎黍匾?那豈不還是很繁瑣。是的锐涯,接下來(lái)我們就對(duì)這些進(jìn)行封裝。

使用compose操作符


public class SchedulersHelper implements FlowableTransformer{

 @Override

 public Publisher apply(Flowable upstream) {

 return upstream.subscribeOn(Schedulers.io())

 .observeOn(AndroidSchedulers.mainThread());

 }

}

使用compose操作符可以直接對(duì)當(dāng)前Flowable進(jìn)行操作全庸,所以我們自然可以把切換線程的操作加入這里秀仲。接下來(lái)就是Subscriber進(jìn)行封裝了壶笼。

封裝Subscriber


public abstract class MySubscriber<T> implements Subscriber<T>{

 @Override

 public void onSubscribe(Subscription s) {

 s.request(Long.MAX_VALUE);

 showLoading();

 }

 @Override

 public void onNext(T t) {

 //code為1代表服務(wù)器返回成功的數(shù)據(jù)

 if (((BaseBean)t).getCode() == 1) {

 //成功后返回data數(shù)據(jù)進(jìn)行處理即可

 onSuccess((T) ((BaseBean) t).getData());

 }else {

 //處理服務(wù)器返回錯(cuò)誤code

 }

 }

 @Override

 public void onComplete() {

 finishLoading();

 }

 @Override

 public void onError(Throwable t) {

 finishLoading();

 //處理網(wǎng)絡(luò)異常

 Log.d("TAG","=========" + t);

 }

 protected abstract void onSuccess(T t);

 protected abstract void showLoading();

 protected abstract void finishLoading();

}

如上所示,我們根據(jù)服務(wù)端返回的code判斷是否成功覆劈,將data數(shù)據(jù)傳出去沛励。服務(wù)器返回的錯(cuò)誤碼和網(wǎng)絡(luò)請(qǐng)求錯(cuò)誤我們都可以統(tǒng)一在這里進(jìn)行處理炮障。然后我們?cè)偃y(cè)試接口。

測(cè)試


HttpRequest.getApi().province()

 .compose(new SchedulersHelper())

 .subscribe(new MySubscriber() {

 @Override

 protected void onSuccess(Object o) {

 }

 @Override

 protected void showLoading() {

 }

 @Override

 protected void finishLoading() {

 }

 });

可以的看到操作流程已經(jīng)變的很簡(jiǎn)單了胁赢,對(duì)于showLoading()finishLoading()這兩個(gè)方法我們可以不需要放在這里面企蹭,這個(gè)是我方便測(cè)試便將其寫(xiě)在里面了智末。

結(jié)束

到這里RxJava + Retrofit的封裝就結(jié)束了,這是一個(gè)很簡(jiǎn)單封裝過(guò)程系馆,沒(méi)有用到太多復(fù)雜的邏輯。比較通俗易懂由蘑,封裝的完善度可能不是很高,大家可以當(dāng)作一個(gè)參考尼酿,用自己的理解爷狈,更好的去封裝它裳擎。之前有寫(xiě)過(guò)一篇簡(jiǎn)單的MVP基類(lèi),這個(gè)封裝過(guò)程我便將它放在了上一篇的項(xiàng)目中句惯。構(gòu)成了一個(gè)簡(jiǎn)單易懂易上手的:RxJava + Retrofit + MVP的小Demo,放在了GitHub上支救,大家可以查看RxRetrofitMvp。如果你覺(jué)對(duì)你有幫助的話請(qǐng)各墨,希望給個(gè)star哦指孤,哈哈哈贬堵!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市黎做,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蒸殿,老刑警劉巖鸣峭,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異摊溶,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)充石,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)骤铃,“玉大人,你說(shuō)我怎么就攤上這事劲厌。” “怎么了补鼻?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)风范。 經(jīng)常有香客問(wèn)我咨跌,道長(zhǎng)硼婿,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任寇漫,我火速辦了婚禮,結(jié)果婚禮上州胳,老公的妹妹穿的比我還像新娘记焊。我一直安慰自己栓撞,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布瓤湘。 她就那樣靜靜地躺著,像睡著了一般弛说。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上木人,一...
    開(kāi)封第一講書(shū)人閱讀 52,196評(píng)論 1 308
  • 那天巾兆,我揣著相機(jī)與錄音,去河邊找鬼角塑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛圃伶,可吹牛的內(nèi)容都是我干的堤如。 我是一名探鬼主播窒朋,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼侥猩!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起欺劳,我...
    開(kāi)封第一講書(shū)人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎划提,沒(méi)想到半個(gè)月后枫弟,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鹏往,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年伊履,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唐瀑。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖介褥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情柔滔,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布萍虽,位于F島的核電站,受9級(jí)特大地震影響杉编,放射性物質(zhì)發(fā)生泄漏咆霜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一嘶朱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧疏遏,春花似錦脉课、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)戳寸。三九已至呈驶,卻和暖如春疫鹊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背订晌。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锈拨,地道東北人砌庄。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓奕枢,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親缝彬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子萌焰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

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