五分钟带你感受RxJava的优雅

1,074 阅读8分钟
原文链接: mp.weixin.qq.com

不知道你有没有发现,在很多互联网公司中,RxJava在开发中占的比例越来越大。

特别是在一些发展速度快,产品迭代更新快的公司中,RxJava经常在面试中出现。

这是一篇RxJava的入门级介绍和接入教程,看完这篇文章你会明白几个问题,· RxJava 是什么· 它的优势在哪里· 怎么应用到项目中

RxJava是什么

RxJava是一个框架,也可以理解为一种代码思路。它的本质思想是观察者模式。拿我们平时经常处理的网络请求场景做例子,数据可以理解为被观察者,UI元素可以理解为观察者。UI元素会根据数据的变化做响应的改变。RxJava就是基于这么种思想的编程风格。

RxJava到现在已经发展到RxJava2了,虽然它的类名和接口名改变了不少,但实际上还是观察者模式。在RxJava中,最基础也是最根本的是两个接口,Observer 和 Observable,这跟Java中的接口名称是一样的。我们以最基础也是最简单的RxJava做demo,来感受下它能给普通的项目带来什么改变。

接入RxJava

在Android中引入RxJava需要添加两个依赖,RxJava和RxAndroid

implementation 'io.reactivex:rxjava:1.3.8'implementation 'io.reactivex:rxandroid:1.2.1'

demo中的例子是用Retrofit来作为网络请求框架,所以还需要添加 Retrofit 的依赖

implementation 'com.squareup.retrofit2:retrofit:2.0.0'implementation 'com.squareup.retrofit2:converter-gson:2.0.0'implementation 'com.squareup.retrofit2:adapter-rxjava:2.0.0'

可能你是第一次用Retrofit还不了解它。OkHttp用过吧?OkHttp是以 Android的 HttpUrlConnection作为基础,封装起来的网络请求库。而Retrofit是以OkHttp为基础封装起来的更简洁的网络请求库,它跟OkHttp是同一个公司的出品。使用Retrofit的原因不仅因为它封装了更简洁的接口,还因为它兼容RxJava。当然你说不用它也可以,OkHttp同样能做一样的事情,甚至手撸HttpUrlConnection也没问题,但那样就没有效率可言了。

代码对比--不使用RxJava

我们写了个demo,用来请求某地区的天气情况,然后更新到UI。demo中用OkHttp来做网络请求,请求返回的json结果封装成 WeatherBean 类。

private void getWeatherJava() {    final Request request = new Request.Builder().url(getWeatherUrl()).build();    okhttp3.Call call = OKHttpManager.getInstance().getClient().newCall(request);    call.enqueue(new okhttp3.Callback() {        @Override        public void onFailure(okhttp3.Call call, IOException e) {            Log.d(TAG, "onFailure: " + e.getMessage());        }        @Override        public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {            try {                if(response.body() != null) {                    String body = response.body().string();                    Log.d(TAG, "onResponse: " + body);                    Type type = new TypeToken<WeatherBean>() {}.getType();                    WeatherBean bean = new Gson().fromJson(body, type); //<--请求结果                    WeatherActivity.this.runOnUiThread(new Runnable() { //<--切换到主线程                        @Override                        public void run() {                            invalidateWeather(bean);                        }                    });                }            } catch (Exception e) {                Log.d(TAG, "onResponse: " + e.getMessage());            }        }    });}/** * @param bean 请求结果 */private void invalidateWeather(WeatherBean bean) {    mLocation.setText(bean.getSys().getCountry());    mTmp.setText(String.valueOf(bean.getMain().getTemp()));}/** * @return 某地区天气请求的url */private String getWeatherUrl() {    String location = "Beijing";    return String.format(AppConstant.URL_CITY, location, AppConstant.APP_KEY);}

这段代码一目了然,这里需要强调一点,在网路请求返回的时候关于线程的问题。对于网络请求这种耗时操作都要开线程去处理,OkHttp在请求结束返回时是处于子线程的。子线程不允许更新UI的问题相信大家都知道,所以这里需要post到当前的Activity去更新UI。

挺简单的一段代码,但我们还是觉得太繁琐。现在我们要用RxJava+Retrofit来修改getWeatherJava()这个方法。

代码对比--RxJava+Retrofit

没使用过Retrofit的话可能需要补充一下相应的知识点。如果懒的跳去看的话也没关系,因为这篇文章的目的是感受RxJava带来的优势和便利性,即使不懂Retrofit,也一样能从代码上感受出来。你可以选择跳过看不懂的地方,直接跳到最后面的 getWeatherRetrofitRx()源码。

这个demo中的Retrofit接口定义是这样的

public interface ApiWeather {    @GET("/data/2.5/weather")    Observable<WeatherBean> getWeather(@Query("q") String city, @Query("APPID") String appid);}

如果你用过Retrofit,这里能看到区别。Retrofit的接口通常是返回Call对象,而这里返回的是Observable对象。这就是Retrofit兼容RxJava的地方,它能直接生成一个Observable对象给RxJava作为链式调用的接收者,所以这也是为什么Retrofit+RxJava能让代码非常优雅的原因。

直接上代码,看看跟用OkHttp的代码的差别在哪里。

private void getWeatherRetrofitRx() {    Retrofit retrofit = new Retrofit.Builder()            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())            .addConverterFactory(GsonConverterFactory.create())//<--Gson转换代码            .baseUrl(AppConstant.ULR)            .build();    ApiWeather apiWeather = retrofit.create(ApiWeather.class);    apiWeather.getWeather("Beijing", AppConstant.APP_KEY)            .subscribeOn(Schedulers.io()) //<--切换到子线程做网络请求            .observeOn(AndroidSchedulers.mainThread()) //<--切换到主线程做UI更新            .subscribe(new Observer<WeatherBean>() {                @Override                public void onCompleted() {                    Log.d(TAG, "onCompleted: ");                }                @Override                public void onError(Throwable e) {                    Log.d(TAG, "onError: ");                }                @Override                public void onNext(WeatherBean bean) {                    Log.d(TAG, "onNext: ");                    invalidateWeather(bean);                }            });}

这段代码是不是非常的简洁?这样就完成了一次网络的请求和UI更新。链式调用+统一缩进,比用OkHttp的代码的阅读性提升了许多。但它的优势不仅如此,RxJava其中一个很重要的特性才是它被普遍使用的原因。那就是线程切换

上面说了,网络请求是在子线程中操作,而更新UI必须在主线程。这也是用OkHttp写的代码读起来难受的原因,因为需要写繁琐的代码去切换线程。甚至在场景复杂的情况下,还需要手撸handler去做这些事情。RxJava免去了这些烦恼,可以看上面这段代码的注释关于线程切换的部分。当你需要把操作放到子线程,只需要subscribeOn(Schedulers.io())当你需要在主线程做响应,只需要observeOn(AndroidSchedulers.mainThread())

而Retrofit还不用你手写Gson转换的模板代码,它都有现成的工具类帮你实现,

.addConverterFactory(GsonConverterFactory.create())//<--Gson转换代码

总结

所以说为什么越来越多的公司开始普及RxJava,我觉得有几个原因· 线程切换· 链式调用· 兼容性好RxJava还有一些更好的特性,这里篇幅所限,我们接下来再陆续举例说明。如果你看了这篇文章想要拿对应的demo来学习的话,可以在后台回复"RxJava"获取源码。

==== 今日沙雕 ====