RxJava 之 Android使用初体验

什么是RxJava##

  • RxJava 就是异步
  • RxJava 的异步实现,是通过一种扩展的观察者模式来实现的。
  • 一个响应式编程框架

通过之前对RxJava的了解,我们已经掌握了RxJava的一些基础使用方法,下面我们结合一个简单的Demo,看看如何在Android 开发中使用RxJava。

RxAndroid 初体验###

需求####

这里我们的需求很简单:
点击按钮,执行一个网络请求,将返回的json信息解析,实现UI 更新

这也是我们做APP最常用的套路。首先看一下,我们需要 实现的效果。

RxAndroid

看到网上关于RxJava的网络请求的内容,都会提及Retrofit的使用,然而由于Retrofit使用了注解相关的内容,代码看起来会有点不好理解,这里我们就从最基础的网络请求出发,一步一步理解一下RxAndroid的使用。

RxAndroid+OkHttp+Gson 实现数据更新####

OkHttp

OKHttp 大家应该都了解,OkHttp 是基于http协议封装的一套请求客户端。具体的细节就不展开说了,这里直接使用。

  • 我们创建OKHttpClient 和 Request
client = new OkHttpClient();
request = new Request.Builder()
                .url(BaseUrl)
                .build();
  • 创建Observeable (OKHttp 同步执行)
private Observable<Response> HttpService() {
        Observable myObserve;

        myObserve = Observable.create(new Observable.OnSubscribe<Response>() {
            @Override
            public void call(Subscriber<? super Response> subscriber) {
                Response response = null;
                try {
                    response = client.newCall(request).execute();
                    subscriber.onNext(response);
                    subscriber.onCompleted();

                } catch (IOException e) {
                    subscriber.onError(e);
                }
            }

        });

这里我们通过oncreate 操作符创建了一个Observeable,在其call 方法中执行了OkHttp的一个同步get请求
网络请求正常时,将请求响应Resoponse通过onNext方法返回,同时执行onCompleted方法。
网络请求异常时,将异常信息通过onError方法返回。

  • 订阅者执行subscribe
private void getData() {
        HttpService()
                .subscribe(new Subscriber<Response>() {
                    @Override
                    public void onCompleted() {
                        Log.e("onCompleted", "onCompleted");
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("onError", e.getMessage());
                    }

                    @Override
                    public void onNext(Response response) {
                        if (response.isSuccessful()) {
                            try {
                                String json = response.body().string();
                                Log.e("onNext", json);
                                setView(json);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }

                    }
                });
    }

通过之前的学习,我们知道在订阅者(Subscribe)实现订阅(subscribe)操作的同时,Observeable就会开始发送事件,在我们当前的例子里,就是开始执行oncall方法,通过OKHttp的网络请求,将请求到的信息Response通过onNext返回,而在订阅者的onNext 方法里,我们处理Response信息,实现UI更新

  • 指定正确的执行线程

你应该已经注意到,上面一个简单的流程里,我们进行了网络请求UI更新等操作,而这些操作必然是在不同的线程中完成,这就要求我们整个操作流程必须实现正确的线程切换,RxJava 固然强大,但也无法实现线程的智能切换 ,必须由我们去指定合适的线程。所以我们上面的代码是有问题的,需要进行如下修改:

private void getData() {
        HttpService()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Response>() {
                   onCompleted();
                    ......unchange
   }

这里我们的修改很简单,两行关键代码:

 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())

这两行代码指定了,我们的网络请求在io线程执行,不会阻塞主线程;UI更新确保在主线程中执行。

总结来说,这里我们使用到了RxJava中的调度器,就是subscribeOn 指定了Observeable 执行的线程;而observeOn指定了Subscribe(订阅者)执行的线程。

这样我们非常简单实现了对线程的控制。

  • 以正确的方式更新UI

好了,我们现在可以放心的执行getData方法了 ,在其onNext 方法,我们接收Response中的数据:

这里分享一下,我在使用这个OKHttp 的Response时遇到一个坑:

Log.e("onNext", response.body().string());
String json = response.body().string();
Log.e("onNext", json);

执行上面的三行代码,你会发现,第一次打印的日志是有数据的,而第二次打印的日志数据却是null,第一次看到这个情况的时候,真的是让我惊呆了,后来看了body 方法的API才明白:

/**
   * Never {@code null}, must be closed after consumption, can be consumed only once.
   */
  public ResponseBody body() {
    return body;
  }

原来这个boby方法只能被执行一次。这个真是有点坑啊!!!!每次获取数据都有打印日志的习惯,真不知道只能执行一次的意义是什么。

好了,我们继续,数据已经能正确接收了,接下来就是解析数据并更新UI 了。

public void setView(String json) {
        Gson gson = new Gson();
        DoubanBean douban = new DoubanBean();
        douban = gson.fromJson(json, DoubanBean.class);
        //
        Glide.with(mContext).load(douban.getIcon()).into(pic);
        title.setText(douban.getTitle());
        id.setText(douban.getId());

    }

这里我们用Gson 解析返回的json 格式数据,实现View 内容更新。

这里我们调用getData方法,结果发现页面没有任何变化,看Logcat日志输出:

E/onError: Permission denied (missing INTERNET permission?)

原来是我们忘记在AndroidManifest 文件中声明网络请求的权限了,这里执行了onError 方法,返回了异常信息。

我们加上INTERNET 相关的权限之后,运行程序,发现可以正常执行了。

这里可以看到,RxJava的响应式编程思想中,对错误的处理也是很理性的。

  • 创建Observeable (OKHttp 异步执行)

之前我们创建Observeable的方式是通过OKHttp的同步get请求方式,如果用异步请求方式怎么做呢?

     // OkHttp 异步执行
        myObserve=Observable.create(new Observable.OnSubscribe<Response>() {
            @Override
            public void call(final Subscriber<? super Response> subscriber) {
                client.newCall(request).enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        subscriber.onError(e);
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        subscriber.onNext(response);
                        subscriber.onCompleted();
                    }
                });
            }
        });

看以看到,和同步请求方式不同的是,我们将onNext ,onCompleted 和 onError这些回调方法放在了OKHttp自己的回调里进行执行。这样做的唯一优点可能就是我们在执行订阅的时候不用指定Observeable(网络请求)执行的线程了,因为他本身就是异步的,就是这里:

private void getData() {
        HttpService()
                //okHttp 异步执行时,无需指定网络请求的线程
//                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .......
    }

当然,OkHttp终究只是对网络请求做了一次封装的库,和最基础的HttpClient, HttpUrlConnection的功能是一样的,不像Volley、android-async-http这些库;无论同步执行还是异步执行,其请求结果始终是在子线程,所以我们的Subscribe对于UI的更新还是需要指定其为mainThread 的。

这里可以看出,使用异步的OKHttp反而有点多余了。

后话###

这里我们通过 RxAndroid+OkHttp+Gson 的方式,以一种最费劲的方式实现了一个简单的需求(这个Demo真的很烂),只是为了阐述RxJava 的编程思想在Android中使用的体验。这里的需求,通过AsnycTask 或者OkHttp + Handler 的方式实现是非常简单的,就不再详述了。

RxJava 的作用就是实现异步,如果我们原本的操作本来就是异步,为了使用RxJava而硬套进去是不合理的,反而显得有点不伦不类,这里我们从Observeable的创建使用OkHttp 的同步&异步请求就可以看出,使用异步请求并没有多大益处,反而丢掉了RxJava可以指定线程的优点。

RxJava的使用并不能使我们的程序运行更高效,或者可以实现了别的框架实现不了的功能。只是对我们编写代码的方式提供了一种更好的思路。


好了,RxJava 基础到这里就结束了。文中所讲的Demo在GitHub中也有,感兴趣的同学可以点这里

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容