我們真的需要使用RxJava+Retrofit嗎?

原文:http://blog.csdn.net/TOYOTA11/article/details/53454925

點擊閱讀原文


RxJava詳解:http://gank.io/post/560e15be2dca930e00da1083

Retrofit詳解:http://www.tuicool.com/articles/AveimyQ


-----------------------------------------------------------------

前言

可以說RxJava+Retrofit是整個2016年Android?開發圈內最受關注的的組合。各大Android論壇上有大量以RxJava+Retrofit+xxx 為標題的文章,此類文章也備受大家的關注。這個組合仿佛已經成為了Android開發的必備組件,項目里沒使用這個組合好像自己都out了似的。

平心而論,RxJava和Retrofit 相較于以往的各種框架(如 AsyncHttpClient,Volley等 )學習和使用起來會有一些難度;RxJava 強大而又龐大的操作符,Retrofit采用注解風格定義接口,都會讓初學者花費不少功夫,繞不少圈子,踩大量的坑。既然這樣,那么就會有人懷疑,我們真的需要學習RxJava和Retrofit嗎?

任意一款需要聯網的APP,最典型的套路就是請求后端數據,解析數據進行UI更新;響應用戶操作,再次請求數據,更新UI。這里我們就從最基礎的網絡請求出發,帶著疑問,逐步了解一下Retrofit的前生今世,看一看RxJava和Retrofit的價值所在。

Android Http

最基礎的實現方式

初學Android開發時,還在上大學,那會兒還不知有AsyncHttpClient,Volley,OKHttp 這么方便的框架;一個簡單的網絡請求通常要寫一大段代碼。

使用HttpURLConnection實現網絡請求####

class MyTask extends AsyncTask<String, Void, String> {@Overrideprotected 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;}@Overrideprotected 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;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
new MyTask().execute(BASE_URL);
  • 1
  • 1

這段代碼的邏輯很簡單,就是將網絡請求的結果顯示在一個TextView上。很大一部分的內容都是在執行HttpURLConnection 相關的配置及初始化工作。

記得第一次通過網絡請求把數據顯示的Android模擬器(那時候還是窮學生,買不起Android手機)的屏幕上時,雖然只是一大堆別人看不懂的json字符串,但是感覺自己就要上天了,現在想想真是。。。。。

即便是這么長的一段代碼,還沒有包含網絡請求異常的內容,如果加上網絡請求失敗處理的邏輯,將使得整個代碼結構更加臃腫龐大。

網絡請求框架的涌現

一款聯網的APP至少會有十幾次的網絡請求,更多的就無法估計了。因此,每一次的網絡請求不可能像上面那樣寫。因此,我們需要封裝,將一些固定的操作統一處理,當然已經有許多大神比我早想到了這個問題,因此便出現了許多對網絡請求進行封裝的庫。

  • AsyncHttpClient(底層基于HttpClient)
  • afinal(FinalHttp,同樣是基于HttpClient封裝)
  • xUtils (基于afinal)
  • Volley(Google官方出品)
  • okHttp
  • NoHttp (個人開發)

這里列出的幾個庫當中,個人使用AsyncHttpClient較多,AsyncHttpClient 的確非常好用,但是后來伴隨著Android sdk 23 中HttpClient的廢棄也逐漸被遺忘。?
afinal和xUtils 都沒有在實際項目中沒用過,不做評價。

Volley作為Google官方在2013年I/O 大會上推出的庫,相較于AsyncHttpClient 更強大。

Volley 簡單使用

這里使用的Volley版本:

compile 'com.mcxiaoke.volley:library:1.0.19'
  • 1
  • 1
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() {@Overridepublic void onClick(View v) {queue.add(request);}});}private class ResponseSuccessListener implements com.android.volley.Response.Listener<String> {@Overridepublic void onResponse(String response) {tv.setText(response);}}private class ResponseFailListener implements Response.ErrorListener {@Overridepublic void onErrorResponse(VolleyError error) {Toast.makeText(mContext, error.toString(), Toast.LENGTH_SHORT).show();}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

這段代碼和上面的功能一樣,都是將網絡請求的結果顯示在TextView。但是通過Volley對http請求進行一次封裝后,我們不再關注網絡請求的具體實現,而是將重點放在了對請求結果的處理上;網絡請求無論成功還是失敗,我們都可以很多好的應對。

而且在Volley中,異步網絡請求的回調方法已然處于UI線程中,這樣我們就可以直接在回調方法中進行UI更新了。

OKHttp 簡單介紹

okHttp 是由squire 推出的一個網絡請求庫,包括Retrofit也是由其開發,這里為squire點個贊。

使用之前加入依賴

    compile 'com.squareup.okhttp3:okhttp:3.4.1'compile 'com.squareup.okio:okio:1.11.0'
  • 1
  • 2
  • 1
  • 2

okHttp 網絡請求實現

findViewById(R.id.get).setOnClickListener(new View.OnClickListener() {@Overridepublic 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 {@Overridepublic void onFailure(Call call, IOException e) {Message msg = new Message();msg.what = 100;msg.obj = e;handler.sendMessage(msg);}@Overridepublic 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 {@Overridepublic 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;}}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

從上面的代碼可以看到,使用OKHttp做異步請求后,在回調方法中,我們使用了Handler。因為這個回調方法并不處于UI線程當中,因此不能直接對UI 進行操作。

這里并不能說OKHttp不夠強大,其實okhttp的封裝套路和Volley,AsyncHttp不是一個級別的,不能和后兩者作比較,okhttp 和HttpClient、HttpUriConneciton 才是一個級別的產物,相較于這兩者,okhttp顯然強大了許多。

所以,OKHttp不僅僅可以用于Android開發,Java開發也是OK的。

Retrofit

A type-safe HTTP client for Android and Java

一個針對Android和Java類型安全的http客戶端

上面這句話,就是Squire對Retrofit的說明,言簡意賅。Retrofit其實是對okhttp 做了進一步的封裝,有了okhttp 的基礎,使用Retrofit會很容易。

為了方便,這里我們使用”https://api.github.com/”作為網絡請求的接口基地址

使用之前加入依賴:

compile 'com.squareup.retrofit2:retrofit:2.1.0'
  • 1
  • 1

定義接口

public interface GithubService {@GET("users/{user}")Call<ResponseBody> getUserString(@Path("user") String user);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

這里我們使用http中的get 方法獲取users這個接口下,當前user的具體信息,參數為當前user名。返回內容為Http請求的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>() {@Overridepublic 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();}}@Overridepublic 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();}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

這里GitHubUserBean為網絡請求結果json數據所對應的實體類。

通過這段代碼,我們在最終的回調方法里可以友好的處理請求結果,失敗時onFailure方法執行。成功時,onResponse方法執行,我們在這里用Gson解析返回的數據,并進行UI更新操作(setUserView(bean)),

這里我們這樣做有些啰嗦,Gson轉換的方式都是類似,唯一不同的只是具體的類;因此我們可以借助強大的Retrofit幫助我們完成Gson轉換的步驟。

添加依賴:

compile 'com.squareup.retrofit2:converter-gson:2.1.0'
  • 1
  • 1

注意這里converter-gson 的版本號,要和之前Retrofit的版本號保持一致。

我們重新定義接口:

public interface GithubService {@GET("users/{user}")Call<GithubUserBean> getUser(@Path("user") String user);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

這里我們用GithubUserBean取代ResponseBody,直接將其作為返回類型。

Retrofit 返回對象

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>() {@Overridepublic void onResponse(Call<GithubUserBean> call, Response<GithubUserBean> response) {GithubUserBean bean = response.body();setUserView(bean);loading.dismiss();}@Overridepublic void onFailure(Call<GithubUserBean> call, Throwable t) {loading.dismiss();}});}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

這里的實現方式和上面基本相似,只是多了一行

.addConverterFactory(GsonConverterFactory.create());
  • 1
  • 1

這樣,我們在onResponse中獲得就是對象,不再需要做額外的轉換工作,可以直接使用。

Retrofit 簡單封裝

這里我們可以看到,Retrofit使用有著一定的套路,所以我們可以將Retrofit初始化相關得內容做一次簡單的封裝。

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>() {@Overridepublic void onResponse(Call<GithubUserBean> call, Response<GithubUserBean> response) {GithubUserBean bean = response.body();loading.dismiss();setUserView(bean);}@Overridepublic void onFailure(Call<GithubUserBean> call, Throwable t) {loading.dismiss();}});}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

我們只需傳入定義好的借口,會使代碼簡介許多。看到這里可以發現,Retrofit的確很厲害,那為什么又要將他和RxJava結合在一起呢?下面我們就來看看。

RxJava+Retrofit

關于什么是RxJava,這里不再贅述,不了解的看以看看這里。這里我們就看看將RxJava 和我們之前的內容結合在一起會有怎樣的效果。

首先,加入依賴

    compile 'io.reactivex:rxjava:1.1.7'compile 'io.reactivex:rxandroid:1.2.1'
  • 1
  • 2
  • 1
  • 2

RxJava+Retrofit 實現

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>() {@Overridepublic 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>() {@Overridepublic GithubUserBean call(GithubUserBean o) {if (TextUtils.isEmpty(o.getBio())) {o.setBio("nothing !");}return o;}}).subscribe(new Subscriber<GithubUserBean>() {@Overridepublic void onCompleted() {loading.dismiss();}@Overridepublic void onError(Throwable e) {loading.dismiss();}@Overridepublic void onNext(GithubUserBean o) {setUserView(o);}});}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

這里有幾點需要注意:

  • RxJava 本身最大的特定就是異步,因此這里我們Retrofit執行網絡請求的時候,使用了execute(同步請求),而不再是enqueue。
  • RxJava 可以使用subscribeOn和observeOn完美處理Observeable和Subscribe的執行線程問題。
  • 這里使用RxJava中map操作符,對返回內容中的為null或“” 的對象做了簡單的處理。

我們引入RxJava實現了同樣的功能,卻使得代碼量增加了。RxJava的價值到底在哪里呢?

RxJava + Retrofit 到底好在哪里

好了,為了說明為題,我們添加一個接口

public interface GithubService {@GET("users/{user}")Call<GithubUserBean> getUser(@Path("user") String user);@GET("users/{user}/followers")Call<List<UserFollowerBean>> getFollowers(@Path("user") String user);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

新增的getFollowers 方法,會返回當前用戶的所有followers list 對象。

private void RxRetrofitList() {GithubService service = GenServiceUtil.createService(GithubService.class);final Call<List<UserFollowerBean>> call = service.getFollowers(name);Observable<List<UserFollowerBean>> myObserve = Observable.create(new Observable.OnSubscribe<List<UserFollowerBean>>() {@Overridepublic void call(Subscriber<? super List<UserFollowerBean>> subscriber) {try {Response<List<UserFollowerBean>> followers = call.execute();subscriber.onNext(followers.body());subscriber.onCompleted();} catch (IOException e) {e.printStackTrace();subscriber.onError(e);}}});myObserve.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<List<UserFollowerBean>>() {@Overridepublic void onCompleted() {loading.dismiss();}@Overridepublic void onError(Throwable e) {loading.dismiss();e.printStackTrace();}@Overridepublic void onNext(List<UserFollowerBean> userFollowerBeen) {setFollowersView(userFollowerBeen);}});}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

在onNext 方法中,接收到返回的對象,更新UI。 這里如果我們不使用RxJava,單獨使用Retrofit實現這個過程是沒有任何問題的; RxJava看似沒有價值;但是假設現在出現如下之一的情景

  • 需要對返回的userFollowerBeen 這個list 進行按用戶名從小到大的排序
  • 需要對返回的userFollowerBeen 這個list 進行按用戶ID從小到大的排序
  • 如果返回的userFollowerBeen 這個list 中,某一項的頭像地址為空,則不顯示該項

…..

這種情景在實際開發中太常見了,而每一次需求的變更都意味著我們需要去修改setFollowersView這個方法,需求一旦變更,就去修改這個方法,這樣會不可避免的產生各種bug。那有沒有辦法不去修改這個方法呢?這個時候,就需要強大的RxJava了。

這里我們就看看如何在不修改setFollowersView的前提下,實現對用戶名從小到大的排序:

private void RxRetrofitList() {GithubService service = GenServiceUtil.createService(GithubService.class);final Call<List<UserFollowerBean>> call = service.getFollowers(name);Observable<List<UserFollowerBean>> myObserve = Observable.create(new Observable.OnSubscribe<List<UserFollowerBean>>() {@Overridepublic void call(Subscriber<? super List<UserFollowerBean>> subscriber) {try {Response<List<UserFollowerBean>> followers = call.execute();subscriber.onNext(followers.body());subscriber.onCompleted();} catch (IOException e) {e.printStackTrace();subscriber.onError(e);}}});myObserve.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).map(new Func1<List<UserFollowerBean>, List<UserFollowerBean>>() {@Overridepublic 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>>() {@Overridepublic List<UserFollowerBean> call(List<UserFollowerBean> userFollowerBean) {Collections.sort(userFollowerBean, new Comparator<UserFollowerBean>() {@Overridepublic int compare(UserFollowerBean o1, UserFollowerBean o2) {return o1.getLogin().compareTo(o2.getLogin());}});return userFollowerBean;}}).subscribe(new Subscriber<List<UserFollowerBean>>() {@Overridepublic void onCompleted() {loading.dismiss();}@Overridepublic void onError(Throwable e) {loading.dismiss();e.printStackTrace();}@Overridepublic void onNext(List<UserFollowerBean> userFollowerBeen) {setFollowersView(userFollowerBeen);}});}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

在代碼中我們使用RxJava的map 操作符,對返回數據做了兩次處理,首先將所有用戶名的首字母轉換為大寫字母;然后對整個list按照用戶名從小到大排序。因為用戶名中同時包含以大小寫字母打頭的內容,所以為了方便,我們進行了一次轉換大寫的操作。

同樣是隨著需求變更,修改代碼;但是你會發現,使用RxJava的方式,會降低出現bug的概率,而且就算是不同的人去改,也會比較方便維護。

看到了吧,這就是RxJava的優點,當然這個例子也只是冰山一角。RxJava的存在不僅僅在于網絡請求,可以用在別的方面;RxJava其實是體現了一種思路,所有對數據的操作都在流上完成,講最終的結果返回給觀察者。同時,如果返回的followers 列表有任何異常,RxJava的onError 方法會執行,這就方便我們去處理異常數據了。

總結

通篇通過對Android 網絡請求各種實現的總結,可以看到 相對于Volley,AsyncHttpClient 等庫,RxJava+Retrofit 的優勢并非特別顯著;在執行效率及功能上并無大的亮點;對Volley進行良好的封裝同樣可以實現類似Retrofit自動轉Gson的功能;RxJava+Retrofit 結合會讓我們寫代碼的方式更加有條理,雖然代碼量會增多,但邏輯的清晰才是最重要的不是嗎?所以,RxJava+Retrofit 組合不失為一種好的選擇。


文中所有源碼地址github

-------------

更多的Java,Angular,Android,大數據,J2EE,Python,數據庫,Linux,Java架構師,:

http://www.cnblogs.com/zengmiaogen/p/7083694.html


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/538866.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/538866.shtml
英文地址,請注明出處:http://en.pswp.cn/news/538866.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python ide如何運行_ide - 如何運行Python程序?

你問我很高興&#xff01; 我正在努力在我們的wikibook中解釋這個問題&#xff08;這顯然是不完整的&#xff09;。 我們正在與Python新手合作&#xff0c;并且必須通過您正在詢問的內容幫助我們&#xff01; Windows中的命令行Python&#xff1a; 使用編輯器中的“保存”或“另…

邏輯回歸算法_算法邏輯回歸

logistic回歸又稱logistic回歸分析&#xff0c;是一種廣義的線性回歸分析模型&#xff0c;常用于數據挖掘&#xff0c;疾病自動診斷&#xff0c;經濟預測等領域。例如&#xff0c;探討引發疾病的危險因素&#xff0c;并根據危險因素預測疾病發生的概率等。以胃癌病情分析為例&a…

使用docker搭建wordpress網站

概述 使用docker的好處就是盡量減少了環境部署&#xff0c;可靠性強&#xff0c;容易維護&#xff0c;我使用docker搭建wordpress的主要目標有下面幾個首先我重新生成數據庫容器可以保證數據庫數據不丟失&#xff0c;重新生成wordpress容器保證wordpress網站數據不丟失&#xf…

XUtils之注解機制詳解

原文&#xff1a;http://blog.csdn.net/rain_butterfly/article/details/37931031 點擊閱讀原文 ------------------------------------------------------ 這篇文章說一下xUtils里面的注解原理。 先來看一下xUtils里面demo的代碼&#xff1a; [java] view plaincopy print?…

oracle ko16mswin949,mysql字符集 - osc_wq7ij8li的個人空間 - OSCHINA - 中文開源技術交流社區...

恰當的字符集&#xff0c;暢快的體驗&#xff01;00、Oracle字符集Subsets and Supersets #子集與超集Table A-11 Subset-Superset PairsSubset(子集)Superset(超集)AR8ADOS710AR8ADOS710TAR8ADOS720AR8ADOS720TAR8ADOS720TAR8ADOS720AR8APTEC715AR8APTEC715TAR8ARABICMACTAR…

曼徹斯特編碼_兩種編碼方式以及兩種幀結構

一、不歸零制編碼(Non-Return to Zero)對于不歸零制編碼是最簡單的一種編碼方式&#xff0c;正電平代表1&#xff0c;負電平代表0。如下圖&#xff1a;其實在不歸零制編碼中有一個很明顯的缺陷&#xff0c;那就是它不是自同步碼。對于上圖&#xff0c;你知道它傳輸的數據是什么…

python用一行代碼編寫一個回聲程序_使用Python的多回聲測驗

我在寫一個程序來管理一個五問多的問題- 關于全球變暖的選擇測驗和計算數字 正確答案。 我首先創建了一本字典&#xff0c;比如&#xff1a;questions \ { "What is the global warming controversy about?": { "A": "the public debate over wheth…

iOS開發學習路線

iOS開發學習路線 前言 這里筑夢師,是一名正在努力學習的iOS開發工程師,目前致力于全棧方向的學習,希望可以和大家一起交流技術,共同進步,用簡書記錄下自己的學習歷程. 個人學習方法分享本文閱讀建議 1.一定要辯證的看待本文. 2.本文主要是本人對iOS開發經驗中總結的知識點 3.本…

Android快速開發框架XUtils

原文地址&#xff1a;http://blog.csdn.net/rain_butterfly/article/details/37812371 點擊閱讀原文 -------------------------------------------- https://github.com/wyouflf/xUtils https://github.com/wyouflf/xUtils3 XUtils是基于afinal開發的&#xff0c;比afina…

oracle查看序列數據語法,oracle查詢各種數據字典的語法

ORACLE的數據字典是數據庫的重要組成部分之一&#xff0c;它隨著數據庫的產生而產生, 隨著數據庫的變化而變化&#xff0c;體現為sys用戶下的一些表和視圖。數據字典名稱是大寫的英文字符。數據字典里存有用戶信息、用戶的權限信息、所有數據對象信息、表的約束條件、統計分析數…

如何安裝python3.8.1_python3.8.1 安裝

Loading...請注意&#xff0c;本文編寫于 217 天前&#xff0c;最后修改于 217 天前&#xff0c;其中某些信息可能已經過時。系統環境&#xff1a;centos 7 安裝依賴項 bash yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-d…

明年新iphone使用增強版5nm芯片_蘋果A15芯片或將采用臺積電5nm+工藝!性能提升極強...

今年蘋果的iPhone 12系列搭載的A14 仿生芯片是今年智能手機市場推出的第一款5nm工藝處理器&#xff0c;處理器的性能也是用戶有目共睹的&#xff0c;相較于之前的芯片性能提升了一大截&#xff0c;有眾多網友也表示&#xff1a;蘋果芯片最大的敵人就是上一代的自己。當然&#…

php中dump怎么使用,php – 如何正確使用print_r或var_dump?

我在調試時經常使用以下代碼段&#xff1a;echo "" . var_dump($var) . "";而且我發現我通常會得到一個很好的可讀輸出.但有時我卻不這樣做.這個例子我現在特別煩惱&#xff1a;$usernamexxxxxx;$passwordxxxxxx;$data_urlhttp://docs.tms.tribune.com/tec…

Spring Framework 5 中的新特性

https://www.ibm.com/developerworks/cn/java/j-whats-new-in-spring-framework-5-theedom/index.html Spring 5 于 2017 年 9 月發布了通用版本 (GA)&#xff0c;它標志著自 2013 年 12 月以來第一個主要 Spring Framework 版本。它提供了一些人們期待已久的改進&#xff0c;還…

怎么計算一組數據的波動_稅控盤數據和小規模增值稅申報表計算結果不一致怎么辦...

a公司為小規模納稅人&#xff0c;于2020年1月申報2019年第四季度增值稅時&#xff0c;是按照金稅盤的數據實際銷售金額為562,563,13元&#xff0c;實際銷售稅額為16,876.87元填寫小規模納稅人增值稅申報表。申報成功后&#xff0c;稅務系統卻跳出比對異常&#xff0c;戶管員要求…

簡單又好看的按鈕,扁平化按鈕。

原文地址&#xff1a;http://blog.csdn.net/peijiangping1989/article/details/19333779 點擊閱讀原文 ----------------------------------------------------------- 今天分享一下流行的扁平化按鈕。完全不需要用到圖片哦。效果圖如下&#xff1a; 里面有2個按鈕都是一樣的…

python輸入三行、能出來三行數據_python 讀入多行數據的實例

一、前言本文主要使用python 的raw_input() 函數讀入多行不定長的數據&#xff0c;輸入結束的標志就是不輸入數字情況下直接回車&#xff0c;并填充特定的數作為二維矩陣二、代碼def get2dlistdata():res []inputline raw_input() #以字符串的形式讀入一行#如果不為空字符串作…

請問,現在android流行什么開源框架?

retrofit2.0RxjavagreenDao3大流行圖片庫p,g,f&#xff08;Picasso&#xff0c;Fresco&#xff0c;Glide&#xff09; 3分鐘全面了解Android主流圖片加載庫 http://blog.csdn.net/carson_ho/article/details/51939774 Retrofit2使用&#xff08;非常簡潔易懂&#xff09; ht…

matlab 銳化降噪,matlab 圖形銳化 濾波

help imreadhelp fspecial imfilt幫助穩定中有較多的示例fspecial 函數功能&#xff1a;產生預定義濾波器格式&#xff1a;Hfspecial(type)Hfspecial(gaussian,n,sigma) 高斯低通濾波器Hfspecial(sobel) Sobel 水平邊緣增強濾波器Hfspecial…

執行 link.exe 時出錯_在20多歲時應該做什么,以避免在30多歲和40多歲時后悔?...

1. 永遠不要以為自己可以&#xff0c;將會或曾經到達過以為是錯誤的。無論是幸福&#xff0c;收入還是心態。在二十多歲的關鍵時期&#xff0c;我有這種心態&#xff0c;對我自己不利。認為自己“實現”是一種靜態的世界觀&#xff0c;阻礙了您的成長。接受這樣的事實&#xff…