前言
可以說(shuō)RxJava+Retrofit是整個(gè)2016年Android 開(kāi)發(fā)圈內(nèi)最受關(guān)注的的組合。各大Android論壇上有大量以RxJava+Retrofit+xxx 為標(biāo)題的文章,此類(lèi)文章也備受大家的關(guān)注。這個(gè)組合仿佛已經(jīng)成為了Android開(kāi)發(fā)的必備組件,項(xiàng)目里沒(méi)使用這個(gè)組合好像自己都o(jì)ut了似的。
平心而論,RxJava和Retrofit 相較于以往的各種框架(如 AsyncHttpClient,Volley等 )學(xué)習(xí)和使用起來(lái)會(huì)有一些難度;RxJava 強(qiáng)大而又龐大的操作符,Retrofit采用注解風(fēng)格定義接口,都會(huì)讓初學(xué)者花費(fèi)不少功夫,繞不少圈子,踩大量的坑。既然這樣,那么就會(huì)有人懷疑,我們真的需要學(xué)習(xí)RxJava和Retrofit嗎?
任意一款需要聯(lián)網(wǎng)的APP,最典型的套路就是請(qǐng)求后端數(shù)據(jù),解析數(shù)據(jù)進(jìn)行UI更新;響應(yīng)用戶(hù)操作,再次請(qǐng)求數(shù)據(jù),更新UI。這里我們就從最基礎(chǔ)的網(wǎng)絡(luò)請(qǐng)求出發(fā),帶著疑問(wèn),逐步了解一下Retrofit的前生今世,看一看RxJava和Retrofit的價(jià)值所在。
Android Http
最基礎(chǔ)的實(shí)現(xiàn)方式
初學(xué)Android開(kāi)發(fā)時(shí),還在上大學(xué),那會(huì)兒還不知有AsyncHttpClient,Volley,OKHttp 這么方便的框架;一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)請(qǐng)求通常要寫(xiě)一大段代碼。
使用HttpURLConnection實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求####
class MyTask extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
InputStream mInputStream = null;
HttpURLConnection connection = getHttpUrlConnection(params[0]);
String result = "";
try {
connection.connect();
int statusCode = connection.getResponseCode();
String response = connection.getResponseMessage();
mInputStream = connection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(mInputStream);
BufferedReader reader = new BufferedReader(inputStreamReader);
StringBuffer sb = new StringBuffer();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
result = "StatusCode: " + statusCode + "\n"
+ "Response" + response + "\n"
+ sb.toString();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
tv.setText(s);
}
}
private HttpURLConnection getHttpUrlConnection(String url) {
HttpURLConnection connection = null;
try {
URL mUrl = new URL(url);
connection = (HttpURLConnection) mUrl.openConnection();
connection.setConnectTimeout(20000);
connection.setReadTimeout(40000);
connection.setRequestMethod("GET");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("Charset", "utf-8");
connection.setRequestProperty("Content-Length", "0");
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return connection;
}
new MyTask().execute(BASE_URL);
這段代碼的邏輯很簡(jiǎn)單,就是將網(wǎng)絡(luò)請(qǐng)求的結(jié)果顯示在一個(gè)TextView上。很大一部分的內(nèi)容都是在執(zhí)行HttpURLConnection 相關(guān)的配置及初始化工作。
記得第一次通過(guò)網(wǎng)絡(luò)請(qǐng)求把數(shù)據(jù)顯示的Android模擬器(那時(shí)候還是窮學(xué)生,買(mǎi)不起Android手機(jī))的屏幕上時(shí),雖然只是一大堆別人看不懂的json字符串,但是感覺(jué)自己就要上天了,現(xiàn)在想想真是。。。。。
即便是這么長(zhǎng)的一段代碼,還沒(méi)有包含網(wǎng)絡(luò)請(qǐng)求異常的內(nèi)容,如果加上網(wǎng)絡(luò)請(qǐng)求失敗處理的邏輯,將使得整個(gè)代碼結(jié)構(gòu)更加臃腫龐大。
網(wǎng)絡(luò)請(qǐng)求框架的涌現(xiàn)###
一款聯(lián)網(wǎng)的APP至少會(huì)有十幾次的網(wǎng)絡(luò)請(qǐng)求,更多的就無(wú)法估計(jì)了。因此,每一次的網(wǎng)絡(luò)請(qǐng)求不可能像上面那樣寫(xiě)。因此,我們需要封裝,將一些固定的操作統(tǒng)一處理,當(dāng)然已經(jīng)有許多大神比我早想到了這個(gè)問(wèn)題,因此便出現(xiàn)了許多對(duì)網(wǎng)絡(luò)請(qǐng)求進(jìn)行封裝的庫(kù)。
- AsyncHttpClient(底層基于HttpClient)
- afinal(FinalHttp,同樣是基于HttpClient封裝)
- xUtils (基于afinal)
- Volley(Google官方出品)
- okHttp
- NoHttp (個(gè)人開(kāi)發(fā))
這里列出的幾個(gè)庫(kù)當(dāng)中,個(gè)人使用AsyncHttpClient較多,AsyncHttpClient 的確非常好用,但是后來(lái)伴隨著Android sdk 23 中HttpClient的廢棄也逐漸被遺忘。
afinal和xUtils 都沒(méi)有在實(shí)際項(xiàng)目中沒(méi)用過(guò),不做評(píng)價(jià)。
Volley作為Google官方在2013年I/O 大會(huì)上推出的庫(kù),相較于AsyncHttpClient 更強(qiáng)大。
下面簡(jiǎn)單列舉一個(gè)使用Volley進(jìn)行g(shù)et請(qǐng)求的demo。
Volley 簡(jiǎn)單使用####
添加依賴(lài):
compile 'com.mcxiaoke.volley:library:1.0.19'
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
queue = Volley.newRequestQueue(mContext);
setContentView(R.layout.activity_http_volley_demo);
tv = (TextView) findViewById(R.id.editText);
final StringRequest request = new StringRequest(Request.Method.GET, BASE_URL,
new ResponseSuccessListener(), new ResponseFailListener());
findViewById(R.id.volley).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
queue.add(request);
}
});
}
private class ResponseSuccessListener implements com.android.volley.Response.Listener<String> {
@Override
public void onResponse(String response) {
tv.setText(response);
}
}
private class ResponseFailListener implements Response.ErrorListener {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(mContext, error.toString(), Toast.LENGTH_SHORT).show();
}
}
這段代碼和上面的功能一樣,都是將網(wǎng)絡(luò)請(qǐng)求的結(jié)果顯示在TextView。但是通過(guò)Volley對(duì)http請(qǐng)求進(jìn)行一次封裝后,我們不再關(guān)注網(wǎng)絡(luò)請(qǐng)求的具體細(xì)節(jié),而是將重點(diǎn)放在了對(duì)請(qǐng)求結(jié)果的處理上;網(wǎng)絡(luò)請(qǐng)求無(wú)論成功還是失敗,我們都可以很多好的應(yīng)對(duì)。
而且在Volley中,異步網(wǎng)絡(luò)請(qǐng)求的回調(diào)方法已然處于UI線(xiàn)程中,這樣我們就可以直接在回調(diào)方法中進(jìn)行UI更新了。
可以說(shuō),使用Volley已經(jīng)可以非常方便的處理Android 網(wǎng)絡(luò)請(qǐng)求的相關(guān)內(nèi)容了。既然如此,為什么還會(huì)有OKHttp和Retrofit的出現(xiàn)呢?他們的優(yōu)勢(shì)又在哪里呢?
OKHttp 簡(jiǎn)單介紹####
okHttp 是由squire 推出的一個(gè)網(wǎng)絡(luò)請(qǐng)求庫(kù),包括Retrofit也是由其開(kāi)發(fā),這里為squire點(diǎn)個(gè)贊。
使用之前加入依賴(lài)
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.squareup.okio:okio:1.11.0'
okHttp 網(wǎng)絡(luò)請(qǐng)求實(shí)現(xiàn)
findViewById(R.id.get).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tv.setText("");
loading.setVisibility(View.VISIBLE);
client = new OkHttpClient();
Request.Builder builder = new Request.Builder()
.url(BASE_URL)
.method("GET", null);
request = builder.build();
Call mCall = client.newCall(request);
mCall.enqueue(new MyCallback());
}
});
private class MyCallback implements Callback {
@Override
public void onFailure(Call call, IOException e) {
Message msg = new Message();
msg.what = 100;
msg.obj = e;
handler.sendMessage(msg);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Message msg = new Message();
msg.what = 200;
msg.obj = response.body().string();
handler.sendMessage(msg);
}
}
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
loading.setVisibility(View.GONE);
switch (msg.what) {
case 100:
Object e = msg.obj;
Toast.makeText(mContext, e.toString(), Toast.LENGTH_SHORT).show();
break;
case 200:
String response = (String) msg.obj;
tv.setText(response);
break;
case 300:
int percent = msg.arg1;
Log.e("llll", "the percent is " + percent);
if (percent < 100) {
progressDialog.setProgress(percent);
} else {
progressDialog.dismiss();
Glide.with(mContext).load(FILE_PATH).into(imageView);
}
break;
default:
break;
}
}
}
這里必須了解的是,okHttp的回調(diào)方法,并不處于UI 線(xiàn)程中,對(duì)網(wǎng)絡(luò)請(qǐng)求結(jié)果如果涉及UI 線(xiàn)程的操作,需要使用Handler。這么看來(lái),okHttp 貌似反而不如Volley了。其實(shí)不然,okhttp的封裝套路和Volley,AsyncHttp不是一個(gè)級(jí)別的,不能和后兩者作比較,okhttp 和HttpClient、HttpUriConneciton 才是一個(gè)級(jí)別的產(chǎn)物,相較于這兩者,okhttp顯然強(qiáng)大了許多。
所以,OKHttp不僅僅可以用于Android開(kāi)發(fā),Java開(kāi)發(fā)也是OK的。
Retrofit
A type-safe HTTP client for Android and Java
一個(gè)針對(duì)Android和Java類(lèi)型安全的http客戶(hù)端
上面這句話(huà),就是Squire對(duì)Retrofit的說(shuō)明,言簡(jiǎn)意賅。Retrofit其實(shí)是對(duì)okhttp 做了進(jìn)一步的封裝,有了okhttp 的基礎(chǔ),使用Retrofit會(huì)很容易。
下面就來(lái)看看,使用Retrofit做網(wǎng)絡(luò)請(qǐng)求又是一種怎樣的體驗(yàn)。
這里為了方便我們使用"https://api.github.com/"作為網(wǎng)絡(luò)請(qǐng)求的接口基地址
使用之前加入依賴(lài):
compile 'com.squareup.retrofit2:retrofit:2.1.0'
定義接口
public interface GithubService {
@GET("users/{user}")
Call<ResponseBody> getUserString(@Path("user") String user);
}
這里我們使用http中的get 方法獲取users這個(gè)接口下,當(dāng)前user的具體信息,參數(shù)為當(dāng)前user名。返回內(nèi)容為Http請(qǐng)求的ResponseBody。
Retrofit 返回ResponseBody
private void SimpleRetrofit() {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(BASE_URL);
Retrofit retrofit = builder.client(httpClient.build()).build();
GithubService simpleService = retrofit.create(GithubService.class);
Call<ResponseBody> call = simpleService.getUserString(name);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
loading.dismiss();
try {
String result = response.body().string();
Gson gson = new Gson();
GithubUserBean bean = gson.fromJson(result, GithubUserBean.class);
setUserView(bean);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
loading.dismiss();
}
});
}
private void setUserView(GithubUserBean user) {
if (user != null) {
viewShell.removeAllViews();
View view = LayoutInflater.from(mContext).inflate(R.layout.user_item_layout, null);
TextView title = (TextView) view.findViewById(R.id.title);
TextView id = (TextView) view.findViewById(R.id.userId);
TextView creteaTime = (TextView) view.findViewById(R.id.createTime);
TextView updateTime = (TextView) view.findViewById(R.id.updateTime);
TextView bio = (TextView) view.findViewById(R.id.bio);
ImageView avatar = (ImageView) view.findViewById(R.id.avatar);
title.setText("Name: " + user.getLogin());
bio.setText("Bio: " + user.getBio());
id.setText("Id: " + String.valueOf(user.getId()));
creteaTime.setText("createTime: " + user.getCreated_at());
updateTime.setText("updateTime: " + user.getUpdated_at());
Glide.with(mContext).load(user.getAvatar_url()).into(avatar);
viewShell.addView(view);
} else {
Toast.makeText(mContext, "result is null", Toast.LENGTH_SHORT).show();
}
}
GitHubUserBean 為網(wǎng)絡(luò)請(qǐng)求結(jié)果json數(shù)據(jù)所對(duì)應(yīng)的實(shí)體類(lèi)。
通過(guò)這段代碼,我們?cè)谧罱K的回調(diào)方法里可以友好的處理請(qǐng)求結(jié)果,失敗時(shí)onFailure方法執(zhí)行。成功時(shí),onResponse方法執(zhí)行,我們?cè)谶@里用Gson解析返回的數(shù)據(jù),并進(jìn)行UI更新操作(setUserView(bean)),
這里我們這樣做有些啰嗦,Gson轉(zhuǎn)換的方式都是類(lèi)似,唯一不同的只是每次網(wǎng)絡(luò)請(qǐng)求結(jié)果對(duì)應(yīng)的實(shí)體類(lèi);因此我們可以借助強(qiáng)大的Retrofit幫助我們完成Gson轉(zhuǎn)換的步驟。當(dāng)然,如果在你所在的開(kāi)發(fā)環(huán)境中,接口返回的并不是json格式的數(shù)據(jù),也沒(méi)有問(wèn)題的。

上圖是Retrofit官網(wǎng)對(duì)可轉(zhuǎn)換類(lèi)型給出的介紹。有這么多種,當(dāng)然了如果你們家服務(wù)器返回的數(shù)據(jù)格式比較神奇,你也可以自定義轉(zhuǎn)換類(lèi)。
好了,言歸正傳,這里還是以Json 格式數(shù)據(jù)為例。
添加依賴(lài):
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
注意這里converter-gson 的版本號(hào),要和之前Retrofit的版本號(hào)保持一致。
我們重新定義接口:
public interface GithubService {
@GET("users/{user}")
Call<GithubUserBean> getUser(@Path("user") String user);
}
這里我們用GithubUserBean取代ResponseBody,直接將其作為返回類(lèi)型。
Retrofit 返回對(duì)象
private void LazyRetrofit() {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.client(httpClient.build()).build();
GithubService service = retrofit.create(GithubService.class);
Call<GithubUserBean> call = service.getUser(name);
call.enqueue(new Callback<GithubUserBean>() {
@Override
public void onResponse(Call<GithubUserBean> call, Response<GithubUserBean> response) {
GithubUserBean bean = response.body();
setUserView(bean);
loading.dismiss();
}
@Override
public void onFailure(Call<GithubUserBean> call, Throwable t) {
loading.dismiss();
}
});
}
這里的實(shí)現(xiàn)方式和上面基本相似,只是多了一行
.addConverterFactory(GsonConverterFactory.create());
這樣,我們?cè)趏nResponse中獲得就是對(duì)象,不再需要做額外的轉(zhuǎn)換工作,可以直接使用。
Retrofit 簡(jiǎn)單封裝
這里我們可以看到,Retrofit使用有著一定的套路,所以我們可以將Retrofit初始化相關(guān)得內(nèi)容做一次簡(jiǎn)單的封裝。
public class GenServiceUtil {
private static final String BASE_URL = "https://api.github.com/";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
private static Retrofit retrofit = builder.client(httpClient.build()).build();
public static <S> S createService(Class<S> serviceClass) {
return retrofit.create(serviceClass);
}
}
private void EasyRetrofit() {
GithubService service = GenServiceUtil.createService(GithubService.class);
Call<GithubUserBean> call = service.getUser(name);
call.enqueue(new Callback<GithubUserBean>() {
@Override
public void onResponse(Call<GithubUserBean> call, Response<GithubUserBean> response) {
GithubUserBean bean = response.body();
loading.dismiss();
setUserView(bean);
}
@Override
public void onFailure(Call<GithubUserBean> call, Throwable t) {
loading.dismiss();
}
});
}
我們只需傳入定義好的借口,會(huì)使代碼簡(jiǎn)介許多。看到這里可以發(fā)現(xiàn),Retrofit的確很厲害,那為什么又要將他和RxJava結(jié)合在一起呢?下面我們就來(lái)看看。
RxJava+Retrofit
關(guān)于什么是RxJava,這里不再贅述,不了解的看以看看這里。這里我們就看看將RxJava 和我們之前的內(nèi)容結(jié)合在一起會(huì)有怎樣的效果。
首先,加入依賴(lài)
compile 'io.reactivex:rxjava:1.1.7'
compile 'io.reactivex:rxandroid:1.2.1'
RxJava+Retrofit 實(shí)現(xiàn)###
private void RxRetrofit() {
GithubService service = GenServiceUtil.createService(GithubService.class);
final Call<GithubUserBean> call = service.getUser(name);
final Observable myObserable = Observable.create(new Observable.OnSubscribe<GithubUserBean>() {
@Override
public void call(Subscriber<? super GithubUserBean> subscriber) {
Response<GithubUserBean> bean = null;
try {
bean = call.execute();
subscriber.onNext(bean.body());
} catch (IOException e) {
e.printStackTrace();
subscriber.onError(e);
}
subscriber.onCompleted();
}
});
myObserable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(new Func1<GithubUserBean, GithubUserBean>() {
@Override
public GithubUserBean call(GithubUserBean o) {
if (TextUtils.isEmpty(o.getBio())) {
o.setBio("nothing !");
}
return o;
}
})
.subscribe(new Subscriber<GithubUserBean>() {
@Override
public void onCompleted() {
loading.dismiss();
}
@Override
public void onError(Throwable e) {
loading.dismiss();
}
@Override
public void onNext(GithubUserBean o) {
setUserView(o);
}
});
}
這里有幾點(diǎn)需要注意:
- RxJava 本身最大的特定就是異步,因此這里我們Retrofit執(zhí)行網(wǎng)絡(luò)請(qǐng)求的時(shí)候,使用了execute(同步請(qǐng)求),而不再是enqueue。
- RxJava 可以使用subscribeOn和observeOn完美處理Observeable和Subscribe的執(zhí)行線(xiàn)程問(wèn)題。
- 這里使用RxJava中map操作符,對(duì)返回內(nèi)容中的為null或“” 的對(duì)象做了簡(jiǎn)單的處理。
我們引入RxJava實(shí)現(xiàn)了同樣的功能,卻使得代碼量增加了很多。不禁要問(wèn),RxJava的價(jià)值到底在哪里呢?
RxJava + Retrofit 到底好在哪里
好了,為了說(shuō)明為題,我們添加一個(gè)接口
public interface GithubService {
@GET("users/{user}")
Call<GithubUserBean> getUser(@Path("user") String user);
@GET("users/{user}/followers")Observable<List<UserFollowerBean>> followers(@Path("user") String usr);
}
當(dāng)然這里依舊需要添加依賴(lài):
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
同時(shí)在Service的封裝方法中添加
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
這樣,RxJava就和Retrofit完美的關(guān)聯(lián)在了一起。
我們?cè)诮涌谥校xfollowers()方法直接返回了Observable,因?yàn)镺bservable是RxJava的源頭,而且Retrofit可以很好的支持RxJava,這樣就非常方便了。
private void RxRetrofitList() {
GithubService service = GenServiceUtil.createService(GithubService.class);
Observable<List<UserFollowerBean>> myObserve = service.followers(name);
myObserve
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<UserFollowerBean>>() {
@Override
public void onCompleted() {
loading.dismiss();
}
@Override
public void onError(Throwable e) {
loading.dismiss();
e.printStackTrace();
}
@Override
public void onNext(List<UserFollowerBean> userFollowerBeen) {
setFollowersView(userFollowerBeen);
}
});
}
在接口中返回的內(nèi)容就是Observable,因此不用再像之前一樣單獨(dú)定義Observable;在onNext 方法中,接收到返回的對(duì)象,更新UI。 這里如果我們不使用RxJava,單獨(dú)使用Retrofit實(shí)現(xiàn)這個(gè)過(guò)程是沒(méi)有任何問(wèn)題的; RxJava看似沒(méi)有價(jià)值;但是假設(shè)現(xiàn)在出現(xiàn)如下之一的情景
- 需要對(duì)返回的userFollowerBeen 這個(gè)list 進(jìn)行按用戶(hù)名從小到大的排序
- 需要對(duì)返回的userFollowerBeen 這個(gè)list 進(jìn)行按用戶(hù)ID從小到大的排序
- 如果返回的userFollowerBeen 這個(gè)list 中,某一項(xiàng)的頭像地址為空,則不顯示該項(xiàng)
.....
這種情景在實(shí)際開(kāi)發(fā)中太常見(jiàn)了,試想如果沒(méi)有RxJava;那么每一次需求的變更都意味著我們需要去修改setFollowersView這個(gè)方法,需求一旦變更,就去修改這個(gè)方法,這樣會(huì)不可避免的產(chǎn)生各種bug。那有沒(méi)有辦法不去修改這個(gè)方法呢?這個(gè)時(shí)候,就需要強(qiáng)大的RxJava了。
這里我們就看看如何在不修改setFollowersView的前提下,實(shí)現(xiàn)對(duì)用戶(hù)名從小到大的排序:
private void RxRetrofitList() {
GithubService service = GenServiceUtil.createService(GithubService.class);
Observable<List<UserFollowerBean>> myObserve = service.followers(name);
myObserve
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(new Func1<List<UserFollowerBean>, List<UserFollowerBean>>() {
@Override
public List<UserFollowerBean> call(List<UserFollowerBean> userFollowerBeen) {
for (UserFollowerBean bean : userFollowerBeen) {
String name = "";
name = bean.getLogin().substring(0, 1).toUpperCase() + bean.getLogin().substring(1, bean.getLogin().length());
bean.setLogin(name);
}
return userFollowerBeen;
}
})
.map(new Func1<List<UserFollowerBean>, List<UserFollowerBean>>() {
@Override
public List<UserFollowerBean> call(List<UserFollowerBean> userFollowerBean) {
Collections.sort(userFollowerBean, new Comparator<UserFollowerBean>() {
@Override
public int compare(UserFollowerBean o1, UserFollowerBean o2) {
return o1.getLogin().compareTo(o2.getLogin());
}
});
return userFollowerBean;
}
})
.subscribe(new Subscriber<List<UserFollowerBean>>() {
@Override
public void onCompleted() {
loading.dismiss();
}
@Override
public void onError(Throwable e) {
loading.dismiss();
e.printStackTrace();
}
@Override
public void onNext(List<UserFollowerBean> userFollowerBeen) {
setFollowersView(userFollowerBeen);
}
});
}
在代碼中我們使用RxJava的map 操作符,對(duì)返回?cái)?shù)據(jù)做了兩次處理,首先將所有用戶(hù)名的首字母轉(zhuǎn)換為大寫(xiě)字母;然后對(duì)整個(gè)list按照用戶(hù)名從小到大排序。因?yàn)橛脩?hù)名中同時(shí)包含以大小寫(xiě)字母打頭的內(nèi)容,所以為了方便,我們進(jìn)行了一次轉(zhuǎn)換大寫(xiě)的操作。
同樣是隨著需求變更,修改代碼;但是你會(huì)發(fā)現(xiàn),使用RxJava的方式,會(huì)降低出現(xiàn)bug的概率,而且就算是不同的人去改,也會(huì)比較方便維護(hù)。
看到了吧,這就是RxJava的優(yōu)點(diǎn),當(dāng)然這個(gè)例子也只是冰山一角。這里提到的map操作符只是RxJava龐大操作符集合中的一員,更特別的是,RxJava的操作符還是可以自定義的,這樣讓我們的代碼有了無(wú)限的可能;RxJava的存在不僅僅在于網(wǎng)絡(luò)請(qǐng)求,可以用在別的方面;RxJava其實(shí)是體現(xiàn)了一種思路,所有對(duì)數(shù)據(jù)的操作都在流上完成,將最終的結(jié)果返回給觀(guān)察者。同時(shí),如果返回的followers 列表有任何異常,RxJava的onError 方法會(huì)執(zhí)行,這就方便我們?nèi)ヌ幚懋惓?shù)據(jù)了。
總結(jié)##
通篇通過(guò)對(duì)Android 網(wǎng)絡(luò)請(qǐng)求各種實(shí)現(xiàn)的總結(jié),可以看到 相對(duì)于Volley,AsyncHttpClient 等庫(kù),RxJava+Retrofit 的優(yōu)勢(shì)并非特別顯著;在執(zhí)行效率及功能上并無(wú)大的亮點(diǎn);對(duì)Volley進(jìn)行良好的封裝同樣可以實(shí)現(xiàn)類(lèi)似Retrofit自動(dòng)轉(zhuǎn)Gson的功能;RxJava+Retrofit 結(jié)合會(huì)讓我們寫(xiě)代碼的方式更加有條理,雖然代碼量會(huì)增多,但邏輯的清晰才是最重要的不是嗎?所以,RxJava+Retrofit 組合不失為一種好的選擇。
所以,RxJava+Retrofit 真的是我們需要的東西呀!
文中所有源碼地址github