RxAndroid结合Retrofit,看看谁才是最佳拍档!
这篇博文酝酿好久了,今天终于下定决心开始写!RxAndroid和Retrofit都算是当下非常流行的Android开发框架,这两个框架光是单独使用就已经爽歪歪了,那么将RxAndroid和Retrofit结合起来,又会有怎样的效果呢?
鉴于很多小伙伴可能还没用过RxJava或者RxAndroid,所以我打算先来介绍一下RxJava和RxAndroid,然后再来介绍RxAndroid和Retrofit组合拳!!
本文主要包括以下三方面内容:
1.RxJava简介
2.RxJava在Android中的使用
3.RxJava配合Retrofit的使用
OK,废话不多说,那就开始吧!
1.RxJava简介
RxJava作为Android开发者的新宠已经有很长一段时间了,用过RxJava的人,都觉得这个东西简单好用,没用过的小伙伴第一次看到RxJava的代码时可能会觉得这个东西非常繁琐,那么今天,我想通过几个简单的非HelloWorld的案例来让大家彻底理解RxJava的使用。
先来看看RxJava的GitHub地址:
https://github.com/ReactiveX/RxJava
将RxJava引入到我们的项目中:
compile 'io.reactivex:rxandroid:1.1.0'
compile 'io.reactivex:rxjava:1.1.0'
那么学习RxJava,先得弄清楚什么是RxJava,关于RxJava的介绍,GitHub上有一句话,
a library for composing asynchronous and event-based programs by using observable sequences.
翻译成中文就是:
RxJava是一个基于可观测序列组成的异步的、基于事件的库。通俗一点说就是RxJava它是一个异步库,这个异步库可以让我们用非常简洁的代码来处理复杂数据流或者事件。OK,那么这是对RxJava的一个基本介绍,接下来我们再来看看RxJava中两个最最基础的概念,一个是Observable,还有一个是Observer,其中Observable我们称之为被观察者,Observer称之为观察者,Observable用户发送消息,而Observer用于消费消息,在实际开发中,我们更多的是选择Observer的一个子类Subscriber来消费消息。在消息发送的过程中,Observable可以发送任意数量任意类型的消息(甚至一个将一个触摸事件当作一个消息发出),当Observable所发送的消息被成功处理或者消息出错时,一个流程结束。Observable会用它的每一个Subscriber(观察者)的onNext方法进行消息处理,在消息成功处理后以onComplete()方法结束流程,如果消息在处理的过程中出现了任何异常,则以onError()方法结束流程。比如下面几行代码:
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("哈哈哈哈");
subscriber.onNext("lalalala");
subscriber.onCompleted();
}
})
.subscribe(new Observer<String>() {
@Override
public void onCompleted() {
Log.d("google_lenve_fb", "onCompleted: onCompleted()");
} @Override
public void onError(Throwable e) {
Log.d("google_lenve_fb", "onError:onError() ");
} @Override
public void onNext(String s) {
Log.d("google_lenve_fb", "onNext: " + s);
}
});
通过调用Observable的create方法来创建一个消息源,在它的onCall方法调用next方法来发送两条消息,当两条消息发送完成之后,调用onComplete方法表示消息发送完毕!subscribe表示订阅一条消息,在订阅的时候我们可以传入一个Observer对象,也可以传入一个Subscriber对象,这两个对象中的方法都是一样的,在onNext方法中处理消息,当消息处理完成之后会自动的调用onComplete方法,如果消息处理过程中出错,则会调用onError方法,上面方法打印的日志如下:
onNext: 哈哈哈哈
onNext: lalalala
onCompleted: onCompleted()
如果我在onNext方法执行一行 1/0 ,onNext方法改成下面的样子:
@Override
public void onNext(String s) {
Log.d("google_lenve_fb", "onNext: " + s);
int i = 1 / 0;
}
这个时候再运行,系统打印的日志如下:
onNext: 哈哈哈哈
onError:onError()
当第一条消息打印出来之后,执行1/0时抛异常,直接调用了onError方法,第二条消息将不再处理。OK,上面的代码是一个小小的案例,RxJava中还有许多好玩的操作符,我们接下来一个一个来看。
在实际开发中,我们的数据来源可能是多种多样的,为了简化数据操作,Observable类为我们提供了许多现成的方法,这些方法都能够极大的简化我们对数据的操作,一个一个来看吧。
1.1 from函数
Observale中的from函数接受一个数组,这个方法返回一个按数组元素的顺序来发射这些数据的Observale,看看下面一行代码:
Observable.from(new String[]{"竹外桃花三两枝", "春江水暖鸭先知"})
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() { } @Override
public void onError(Throwable e) { } @Override
public void onNext(String s) {
Log.d("google_lenve_fb", "onNext: " + s);
}
});
这里的观察者我使用了Subscriber,它是Observer的一个实现类。这里打印的结果如下:
D/google_lenve_fb: onNext: 竹外桃花三两枝
D/google_lenve_fb: onNext: 春江水暖鸭先知
按顺序将from函数中数组的值一个一个打印出来了。OK,接着往下看:
1.2 just函数
just函数它接受最多10个参数,返回一个按参数顺序发射这些数据的Observable,代码如下:
Observable.just("Hello", "World", "Hello", "RxJava!","塞外秋来风景异","衡阳雁去无留意"
,"四面边声连角起","千嶂里","长烟落日孤城闭","浊酒一杯家万里")
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() { } @Override
public void onError(Throwable e) { } @Override
public void onNext(String s) {
Log.d("google_lenve_fb", "onNext: " + s);
}
});
打印结果如下:
D/google_lenve_fb: onNext: Hello
D/google_lenve_fb: onNext: World
D/google_lenve_fb: onNext: Hello
D/google_lenve_fb: onNext: RxJava!
D/google_lenve_fb: onNext: 塞外秋来风景异
D/google_lenve_fb: onNext: 衡阳雁去无留意
D/google_lenve_fb: onNext: 四面边声连角起
D/google_lenve_fb: onNext: 千嶂里
D/google_lenve_fb: onNext: 长烟落日孤城闭
D/google_lenve_fb: onNext: 浊酒一杯家万里
1.3map函数
map函数可以对Observable创建的原始数据进行二次加工,然后再被观察者获取。比如下面一段代码,我给原始数据的每一项都追加一个字符串,然后返回:
Observable.from(new String[]{"醉里挑灯看剑","梦回吹角连营"})
.map(new Func1<String, String>() {
@Override
public String call(String s) {
return s + "---辛弃疾";
}
})
.subscribe(new Observer<String>() {
@Override
public void onCompleted() { } @Override
public void onError(Throwable e) { } @Override
public void onNext(String s) {
Log.d("google_lenve_fb", "onNext: " + s);
}
});
打印结果如下:
D/google_lenve_fb: onNext: 醉里挑灯看剑---辛弃疾
D/google_lenve_fb: onNext: 梦回吹角连营---辛弃疾
RxJava的使用都是链式编程,使用map函数时数据来源可以各种各样。
1.4flatMap函数
flatMap函数接受一个Observable函数作为输入函数,然后在这个输入的基础上再创建一个新的Observable进行输出,比如下面一段代码:
Observable.just("落霞与孤鹜齐飞", "秋水共长天一色")
.flatMap(new Func1<String, Observable<String>>() {
@Override
public Observable<String> call(String s) {
return Observable.from(new String[]{s + "冯唐易老", s + "李广难封"});
}
}).subscribe(new Subscriber<String>() {
@Override
public void onCompleted() { } @Override
public void onError(Throwable e) { } @Override
public void onNext(String s) {
Log.d("google_lenve_fb", "onNext: " + s);
}
});
打印结果:
D/google_lenve_fb: onNext: 落霞与孤鹜齐飞冯唐易老
D/google_lenve_fb: onNext: 落霞与孤鹜齐飞李广难封
D/google_lenve_fb: onNext: 秋水共长天一色冯唐易老
D/google_lenve_fb: onNext: 秋水共长天一色李广难封
1.5 scan函数
scan函数是一个累加器函数,对于Observable发射的每项数据进行累加,并将累加的结果返回,如下:
Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.scan(new Func2<Integer, Integer, Integer>() {
@Override
public Integer call(Integer integer, Integer integer2) {
return integer + integer2;
}
})
.subscribe(new Observer<Integer>() {
@Override
public void onCompleted() { } @Override
public void onError(Throwable e) { } @Override
public void onNext(Integer integer) {
Log.d("google_lenve_fb", "onNext: " + integer);
}
});
Observable.from(new String[]{"明", "月", "别", "枝", "惊", "鹊"})
.scan(new Func2<String, String, String>() {
@Override
public String call(String s, String s2) {
return s + s2;
}
})
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() { } @Override
public void onError(Throwable e) { } @Override
public void onNext(String s) {
Log.d("google_lenve", "onNext: " + s);
}
});
打印结果如下:
D/google_lenve_fb: onNext: 1
D/google_lenve_fb: onNext: 3
D/google_lenve_fb: onNext: 6
D/google_lenve_fb: onNext: 10
D/google_lenve_fb: onNext: 15
D/google_lenve_fb: onNext: 21
D/google_lenve_fb: onNext: 28
D/google_lenve_fb: onNext: 36
D/google_lenve_fb: onNext: 45
D/google_lenve_fb: onNext: 55
D/google_lenve: onNext: 明
D/google_lenve: onNext: 明月
D/google_lenve: onNext: 明月别
D/google_lenve: onNext: 明月别枝
D/google_lenve: onNext: 明月别枝惊
D/google_lenve: onNext: 明月别枝惊鹊
1.6elementAt函数
elementAt函数表示获取数据源中的第N项数据输出,如下:
Observable.just("清", "风", "半", "夜", "鸣", "蝉")
.elementAt(4)
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() { } @Override
public void onError(Throwable e) { } @Override
public void onNext(String s) {
Log.d("google_lenve", "onNext: "+s);
}
});
打印结果如下:
D/google_lenve: onNext: 鸣
1.7merge函数
merge函数可以用来合并多个Observable数据源,然后将合并后的数据在一起输出,如下:
Observable<String> observable1 = Observable.just("十里楼台倚翠薇", "百花深处杜鹃啼");
Observable<String> observable2 = Observable.just("殷勤自与行人语","不似流莺取次飞");
Observable.merge(observable1, observable2)
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() { } @Override
public void onError(Throwable e) { } @Override
public void onNext(String s) {
Log.d("google_lenve", "onNext: "+s);
}
});
打印结果如下:
D/google_lenve: onNext: 十里楼台倚翠薇
D/google_lenve: onNext: 百花深处杜鹃啼
D/google_lenve: onNext: 殷勤自与行人语
D/google_lenve: onNext: 不似流莺取次飞
1.8 zip函数
zip函数用来合并多个Observable的数据源,但是与merge不同的是,zip函数中可以对数据源进行二次操作,而不是简单的合并,代码如下:
Observable<String> observable1 = Observable.just("十里楼台倚翠薇", "百花深处杜鹃啼");
Observable<String> observable2 = Observable.just("问君能有几多愁","恰似一江春水向东流");
Observable.zip(observable1, observable2, new Func2<String, String, Object>() {
@Override
public Object call(String s, String s2) {
return s+s2;
}
})
.subscribe(new Subscriber<Object>() {
@Override
public void onCompleted() { } @Override
public void onError(Throwable e) { } @Override
public void onNext(Object o) {
Log.d("google_lenve", "onNext: "+o.toString());
}
});
打印日志如下:
D/google_lenve: onNext: 十里楼台倚翠薇问君能有几多愁
D/google_lenve: onNext: 百花深处杜鹃啼恰似一江春水向东流
1.9其他的过滤函数
Observable函数中还有其他一些好用的过滤函数,我就不再一一演示了,小伙伴们看下面的代码自行试验即可:
private void m7() {
Observable.just(10, 12, 13, 14, 15, 16, 16, 16, 17, 18)
//在数据序列的开头插入一条指定的项1
.startWith(2)
.filter(new Func1<Integer, Boolean>() {
@Override
public Boolean call(Integer integer) {
return integer > 0;
}
})
//只发射前N个元素
.take(2)
//只发射最后N个元素
.takeLast(2)
//只发射第一个元素
.first()
//只发射最后一个元素
.last()
//跳过前两个
.skip(2)
//跳过最后两个
.skipLast(2)
//数据过滤,过滤掉重复数据
.distinct()
.subscribe(new Observer<Integer>() {
@Override
public void onCompleted() { } @Override
public void onError(Throwable e) { } @Override
public void onNext(Integer integer) {
Log.d("google_lenve_fb", "onNext: " + integer);
}
});
1.10 subscribeOn函数和observeOn函数
这两个函数在我们Android开发中还是非常有用的,其中subscribeOn表示指定被观察者执行的线程,而observeOn则表示观察者执行的线程,这个解决网络访问还是非常方便的,如下:
Observable<String> observable1 = Observable.just("十里楼台倚翠薇", "百花深处杜鹃啼");
Observable<String> observable2 = Observable.just("问君能有几多愁","恰似一江春水向东流");
Observable.zip(observable1, observable2, new Func2<String, String, Object>() {
@Override
public Object call(String s, String s2) {
Log.d("google_lenve", "call: "+Thread.currentThread().getName());
return s+s2;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Object>() {
@Override
public void onCompleted() { } @Override
public void onError(Throwable e) { } @Override
public void onNext(Object o) {
Log.d("google_lenve", "onNext: "+Thread.currentThread().getName()+"--------"+o.toString());
}
});
打印日志如下:
D/google_lenve: call: RxCachedThreadScheduler-1
D/google_lenve: call: RxCachedThreadScheduler-1
D/google_lenve: onNext: main--------十里楼台倚翠薇问君能有几多愁
D/google_lenve: onNext: main--------百花深处杜鹃啼恰似一江春水向东流
2.RxJava在Android中的使用
RxJava在安卓开发中不仅能够处理简单的数据流,最好玩的地方莫过于网络访问,我举一个例子(其他的数据流处理这里就不再介绍了),比如我有一个按钮,点击该按钮加载一张图片出来,代码如下:
Observable.create(new Observable.OnSubscribe<Bitmap>() {
@Override
public void call(Subscriber<? super Bitmap> subscriber) {
subscriber.onNext(getBitmap());
}
})
//设置数据加载在子线程进行
.subscribeOn(Schedulers.io())
//设置图片加载在主线程进行
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Bitmap>() {
@Override
public void onCompleted() { } @Override
public void onError(Throwable e) { } @Override
public void onNext(Bitmap bitmap) {
iv.setImageBitmap(bitmap);
}
});
getBitmap方法如下:
private Bitmap getBitmap() {
HttpURLConnection con;
try {
URL url = new URL("http://img3.cache.netease.com/photo/0008/2016-08-10/BU4A81A72ODN0008.550x.0.jpg");
con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(5 * 1000);
con.connect();
if (con.getResponseCode() == 200) {
return BitmapFactory.decodeStream(con.getInputStream());
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
有没有感觉爽歪歪呢?从此彻底告别Handler,告别new Thread。。。。。
3.RxJava配合Retrofit的使用
最后我们再来看看当下最流行的两个框架的组合使用!如果你还不了解Retrofit的使用,参考我之前的博客一个App带你学会Retrofit2.0,麻麻再也不用担心我的网络请求了!
将RxJava和Retrofit结合的时候,首先先修改gradle文件,先把我的gradle文件拿出来给大家瞧瞧:
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'io.reactivex:rxandroid:1.1.0'
compile 'io.reactivex:rxjava:1.1.0'
APIService中的定义如下:
public interface APIService {
@GET("api/lore/classify")
Observable<ClassfyBean> getClassfyBean();
}
创建Retrofit同时创建APIService的实例,代码如下:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.tngou.net")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
APIService apiService = retrofit.create(APIService.class);
注意,这里和我们在一般场景下使用Retrofit有一个区别,那就是多了addCallAdapterFactory这个方法,这里我们添加的RxJava的适配工厂。然后我们就可以调用APIService中的方法来访问网络数据了,如下:
observable
//在子线程访问数据
.subscribeOn(Schedulers.io())
//在主线程显示数据
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<ClassfyBean>() {
@Override
public void onCompleted() { } @Override
public void onError(Throwable throwable) { } @Override
public void onNext(ClassfyBean classfyBean) {
StringBuffer sb = new StringBuffer();
for (ClassfyBean.TngouBean tngouBean : classfyBean.getTngou()) {
sb.append(tngouBean.getName() + "\n");
}
tv.setText(sb.toString());
}
});
OK,这才是网络访问和数据处理最佳拍档。
今天先这样,后面再找时间详细介绍这两个结合的条条框框。。。。
以上。
另外推荐两篇大神文章:
http://wuxiaolong.me/2016/01/18/rxjava/
http://gank.io/post/560e15be2dca930e00da1083
RxAndroid结合Retrofit,看看谁才是最佳拍档!的更多相关文章
- Android RxJava/RxAndroid结合Retrofit使用
概述 RxJava是一个在 Java VM 上使用可观測的序列来组成异步的.基于事件的程序的库.更重要的是:使用RxJava在代码逻辑上会非常简洁明了,尤其是在复杂的逻辑上.告别迷之缩进. RxAnd ...
- 浅谈 RxAndroid + Retrofit + Databinding
http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0131/3930.html 最近 RxAndroid .MVP.MVVM 一直是 And ...
- RxJava + Retrofit完成网络请求
1.前言 本文基于RxJava.Retrofit的使用,若是对RxJava或Retrofit还不了解的简友可以先了解RxJava.Retrofit的用法再来看这篇文章. 在这片文章之前分别单独介绍过R ...
- Retrofit 2.0:有史以来最大的改进
因为其简单与出色的性能,Retrofit 是安卓上最流行的HTTP Client库之一. 不过它的缺点是在Retrofit 1.x中没有直接取消正在进行中任务的方法.如果你想做这件事必须手动杀死,而这 ...
- RxJava+Retrofit+MVP构建的App——聚合资讯
RtfRxMVP 聚合资讯APP,提供热点资讯,天气预报以及笑话精选服务,使用 Retrofit + RxJava + MVP 构建代码. Hello U 这是我的一个练习项目,第一次尝试运用 MVP ...
- retrofit+RXjava二次封装
接入说明:项目中已集成RXjava,RXandroid.Retrofit,为避免包冲突,不须要再次接入. 就可以直接使用RXjava,Retrofit的所有api. github地址:https:// ...
- Rxjava+retrofit+mvp整合
转载请标明出处: http://blog.csdn.net/forezp/article/details/52621898 本文出自方志朋的博客 最近在看Rxjava,写了一个简单的 demo整合了R ...
- 一个响应式数据库框架SQLBrite,完美解决数据库和UI的同步更新!
相信小伙伴们在开发中或多或少都可能遇到过这样的问题:打开一个应用后,为了快速响应,先将数据库中的数据呈现给用户,然后再去网络上请求数据,请求成功之后将数据缓存至数据库,同时更新UI,但是我们经常会这样 ...
- Android实现文章+评论(MVP,RxJava,Dagger2,ButterKnife)
简介 这个项目主要有两个功能,一个加载网页/文章,另一个用来显示评论.并应用了MVP模式,Dagger2.RxJava.ButterKnife等开源框架.效果图如下: 结构 首先来看一下布局文件: & ...
随机推荐
- Android 关于显示键盘,布局错乱网上顶的问题
<activity android:name="com.taiyi.DiscussActivity" android:windowSoftInputMode="st ...
- 【HDOJ】3275 Light
这就是个简单线段树+延迟标记.因为对bool使用了~而不是!,wa了一下午找不到原因. /* 3275 */ #include <iostream> #include <sstrea ...
- How to: Define a Windows Communication Foundation Service Contract
This is the first of six tasks required to create a basic Windows Communication Foundation (WCF) app ...
- 【 D3.js 选择集与数据详解 — 2 】 使用data()绑定数据
D3 中绑定数据大多是由 data() 函数来完成的,它是怎样工作的,它与 datum() 有什么区别呢? data()函数能够将数组各项分别绑定到各元素上,而且能够设置绑定的规则.data()还能够 ...
- Eclipse 中使用Genymotion 作为模拟器的步骤
我这里是先安装的genymotion, 后安装的eclipse. 1:安装genymotion 无难度, 直接安装就行了. 2:安装eclipse 下载adt即可, 解压运行. 3:运行eclipse ...
- web网站加速之CDN(Content Delivery Network)技术原理
在不同地域的用户访问网站的响应速度存在差异,为了提高用户访问的响应速度.优化现有Internet中信息的流动,需要在用户和服务器间加入中间层CDN. 使用户能以最快的速度,从最接近用户的地方获得所需的 ...
- BrnShop开源网上商城第三讲:插件的工作机制
这几天BrnShop的开发工作比较多,所以这一篇文章来的晚了一些,还请大家见谅呀!还有通知大家一下BrnShop1.0.312版本已经发布,此版本添加了报表统计等新功能,需要源码的园友可以点此下载.好 ...
- ARM-Linux配置DHCP自动获取IP地址
备注:内核版本:2.6.30.9busybox版本:1.15.2 PC Linux和开发板Linux的工作用户:root 1. 配置内核:[*] Networking support --->N ...
- POJ 2240 Arbitrage spfa 判正环
d[i]代表从起点出发可以获得最多的钱数,松弛是d[v]=r*d[u],求最长路,看有没有正环 然后这题输入有毒,千万别用cin 因为是大输入,组数比较多,然后找字符串用strcmp就好,千万不要用m ...
- [转]ASP.NET MVC 入门2、项目的目录结构与核心的DLL
我们新建一个ASP.NET MVC的Web Application后,默认的情况下,项目的目录结构如下: App_Data :这个目录跟我们一般的ASP.NET website是一样的,用于存放数据. ...