我们真的需要使用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.mzph.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…