- 前言
RxJava出來(lái)已經(jīng)很久了,2.x版本都已經(jīng)有了,但是掌握的人還是很少。原因有難度太大,操作符太多,不知道它具體有什么用,原來(lái)掌握的庫(kù)在開(kāi)發(fā)中已經(jīng)夠用了,懶得去學(xué)。這些原因里面有些是客觀的比如操作符確實(shí)是太多了,掌握起來(lái)難度還是挺大的,剩余的一些基本就是借口了,給自己逃避找個(gè)理由安慰下自己罷了。當(dāng)然我自己也是找理由中的一份子,2.x版本的RxJava出來(lái)都已經(jīng)很久了,自己連RxJava1.x版本都沒(méi)接觸過(guò)。不過(guò)這也是算是個(gè)好事吧,自己1.x版本可以不用學(xué)了,可以直接學(xué)2.x版本了,福兮禍所依就是這個(gè)道理吧,哈哈!所以本篇都是基于RxJava2.x版本的,同時(shí)開(kāi)篇會(huì)直接引入具體用法,讓你知道用處之后才有動(dòng)力去學(xué),不然一上來(lái)就是一堆的操作符,會(huì)讓你完全沒(méi)有繼續(xù)學(xué)下去的興趣。好了,閑話就扯到這么多了,向上吧,少年! - RxJava是什么?
RxJava 在 GitHub 主頁(yè)上的自我介紹是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一個(gè)在 Java VM 上使用可觀測(cè)的序列來(lái)組成異步的、基于事件的程序的庫(kù))。這就是 RxJava ,概括得非常精準(zhǔn),但是其實(shí)還是不明白,太正式了一點(diǎn)都不接地氣。說(shuō)白了RxJava就是個(gè)實(shí)現(xiàn)異步操作的庫(kù),和Android中現(xiàn)成的 AsyncTask / Handler達(dá)到的目的是一樣的;那么既然Android已經(jīng)有了現(xiàn)成的了,我們?yōu)槭裁催€要去重新學(xué)一個(gè)難度這么大的新東西呢?答案就是RxJava能隨著程序邏輯變得越來(lái)越復(fù)雜,依然能夠保持簡(jiǎn)潔,這里的簡(jiǎn)潔并不是代碼量的多少?。ㄒ话愦a量少的反而可讀性差),而是代碼結(jié)構(gòu)簡(jiǎn)單明了,可讀性很好。說(shuō)了這么多還是貼段代碼來(lái)的實(shí)在:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
Log.e(TAG, "Observable thread is : " + Thread.currentThread().getName());
e.onNext(1);
e.onComplete();
}
})
.subscribeOn(Schedulers.newThread())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
Log.e(TAG, "After observeOn(mainThread),Current thread is " + Thread.currentThread().getName());
}
})
.observeOn(Schedulers.io())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
Log.e(TAG, "After observeOn(io),Current thread is " + Thread.currentThread().getName());
}
});
怎么樣,是不是感覺(jué)結(jié)構(gòu)很清晰,很有層次感,看起來(lái)干凈整潔很舒服。更加重要的是邏輯簡(jiǎn)潔,一條從上到下的鏈?zhǔn)秸{(diào)用,沒(méi)有任何嵌套,能讓開(kāi)發(fā)者快速讀懂,從而提升開(kāi)發(fā)效率。
- EventBus和RxJava對(duì)比
網(wǎng)上有很多說(shuō)RxJava取代了EventBus的說(shuō)法,所以我就在這把這兩個(gè)庫(kù)做個(gè)對(duì)比。其實(shí)這兩個(gè)庫(kù)的設(shè)計(jì)初衷和使用場(chǎng)景是不是一樣的,并不存在說(shuō)誰(shuí)取代誰(shuí)、誰(shuí)優(yōu)誰(shuí)劣的說(shuō)法,大家會(huì)把它們放一起比較主要是因?yàn)樗鼈兌际遣捎糜^察者模。RxJava是為了更方便的處理異步事件流,而EventBus就是為了處理事件分發(fā),功能類似java中的觀察者模式和Android中的廣播,但是實(shí)現(xiàn)起來(lái)比這兩個(gè)簡(jiǎn)單方便。
二者區(qū)別如下:
1、RxJava有大量豐富強(qiáng)大的operator,可以滿足用戶的大部分?jǐn)?shù)據(jù)處理需求。RxJava另一個(gè)強(qiáng)大的地方就是scheduler,用戶可以為Observable和Subscriber指定不同的執(zhí)行線程,在Android中可以方便的將Observable指定在IO線程中運(yùn)行,Subscriber在UI線程中運(yùn)行。
2、EventBus比較適合僅僅當(dāng)做組件間的通訊工具使用,主要用來(lái)傳遞消息。使用EventBus可以避免搞出一大推的interface,僅僅是為了實(shí)現(xiàn)組件間的通訊,而不得不去實(shí)現(xiàn)那一推的接口。
具體用法
操作符和基礎(chǔ)沒(méi)講一上來(lái)就上實(shí)例看不懂是很正常的,但是這樣講的目的前面也提過(guò)了帶著目的性去學(xué)習(xí)這樣效果會(huì)更好??床欢来蟾庞梅ň秃昧?,基礎(chǔ)和操作符會(huì)留到下篇中去講,明確目標(biāo)之后再去學(xué)習(xí)下篇這樣會(huì)更加高效。
在app的build.gradle中添加RxJava依賴
dependencies {
//添加RxJava依賴
implementation "io.reactivex.rxjava2:rxjava:2.2.3"
//添加RxAndroid依賴,專門用于Android的Rx庫(kù)
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
}
天氣信息的網(wǎng)絡(luò)請(qǐng)求
- 通過(guò) Observable.create() 方法創(chuàng)建被觀察者,調(diào)用 OkHttp 進(jìn)行網(wǎng)絡(luò)請(qǐng)求;
- 通過(guò) map 操作符結(jié)合FastJson對(duì)請(qǐng)求結(jié)果解析,將 Response 轉(zhuǎn)換為 bean 類;
- 通過(guò) doOnNext() 方法,進(jìn)行一些其它操作;
- 調(diào)度線程,在子線程中進(jìn)行耗時(shí)操作任務(wù),在主線程中更新 UI ;
- 觀察者通過(guò) subscribe()訂閱事件,根據(jù)請(qǐng)求成功或者失敗來(lái)更新 UI 。
1、準(zhǔn)備工作
-
請(qǐng)求結(jié)果Json如下圖:
天氣.png
2、添加OkHttp和FastJson依賴
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
implementation 'com.alibaba:fastjson:1.1.68.android'
3、聲明網(wǎng)絡(luò)權(quán)限
<uses-permission android:name="android.permission.INTERNET"/>
4、創(chuàng)建天氣返回結(jié)果WeatherBean對(duì)象
public class WeatherBean {
private String success;
private Result result;
public void setSuccess(String success) {
this.success = success;
}
public String getSuccess() {
return this.success;
}
public void setResult(Result result) {
this.result = result;
}
public Result getResult() {
return this.result;
}
class Result {
private String weaid;
private String days;
private String week;
private String cityno;
private String citynm;
private String cityid;
private String temperature;
private String temperature_curr;
private String humidity;
private String aqi;
private String weather;
private String weather_curr;
private String weather_icon;
private String weather_icon1;
private String wind;
private String winp;
private String temp_high;
private String temp_low;
private String temp_curr;
private String humi_high;
private String humi_low;
private String weatid;
private String weatid1;
private String windid;
private String winpid;
private String weather_iconid;
public void setWeaid(String weaid) {
this.weaid = weaid;
}
public String getWeaid() {
return this.weaid;
}
public void setDays(String days) {
this.days = days;
}
public String getDays() {
return this.days;
}
public void setWeek(String week) {
this.week = week;
}
public String getWeek() {
return this.week;
}
public void setCityno(String cityno) {
this.cityno = cityno;
}
public String getCityno() {
return this.cityno;
}
public void setCitynm(String citynm) {
this.citynm = citynm;
}
public String getCitynm() {
return this.citynm;
}
public void setCityid(String cityid) {
this.cityid = cityid;
}
public String getCityid() {
return this.cityid;
}
public void setTemperature(String temperature) {
this.temperature = temperature;
}
public String getTemperature() {
return this.temperature;
}
public void setTemperature_curr(String temperature_curr) {
this.temperature_curr = temperature_curr;
}
public String getTemperature_curr() {
return this.temperature_curr;
}
public void setHumidity(String humidity) {
this.humidity = humidity;
}
public String getHumidity() {
return this.humidity;
}
public void setAqi(String aqi) {
this.aqi = aqi;
}
public String getAqi() {
return this.aqi;
}
public void setWeather(String weather) {
this.weather = weather;
}
public String getWeather() {
return this.weather;
}
public void setWeather_curr(String weather_curr) {
this.weather_curr = weather_curr;
}
public String getWeather_curr() {
return this.weather_curr;
}
public void setWeather_icon(String weather_icon) {
this.weather_icon = weather_icon;
}
public String getWeather_icon() {
return this.weather_icon;
}
public void setWeather_icon1(String weather_icon1) {
this.weather_icon1 = weather_icon1;
}
public String getWeather_icon1() {
return this.weather_icon1;
}
public void setWind(String wind) {
this.wind = wind;
}
public String getWind() {
return this.wind;
}
public void setWinp(String winp) {
this.winp = winp;
}
public String getWinp() {
return this.winp;
}
public void setTemp_high(String temp_high) {
this.temp_high = temp_high;
}
public String getTemp_high() {
return this.temp_high;
}
public void setTemp_low(String temp_low) {
this.temp_low = temp_low;
}
public String getTemp_low() {
return this.temp_low;
}
public void setTemp_curr(String temp_curr) {
this.temp_curr = temp_curr;
}
public String getTemp_curr() {
return this.temp_curr;
}
public void setHumi_high(String humi_high) {
this.humi_high = humi_high;
}
public String getHumi_high() {
return this.humi_high;
}
public void setHumi_low(String humi_low) {
this.humi_low = humi_low;
}
public String getHumi_low() {
return this.humi_low;
}
public void setWeatid(String weatid) {
this.weatid = weatid;
}
public String getWeatid() {
return this.weatid;
}
public void setWeatid1(String weatid1) {
this.weatid1 = weatid1;
}
public String getWeatid1() {
return this.weatid1;
}
public void setWindid(String windid) {
this.windid = windid;
}
public String getWindid() {
return this.windid;
}
public void setWinpid(String winpid) {
this.winpid = winpid;
}
public String getWinpid() {
return this.winpid;
}
public void setWeather_iconid(String weather_iconid) {
this.weather_iconid = weather_iconid;
}
public String getWeather_iconid() {
return this.weather_iconid;
}
@Override
public String toString() {
return "Result{" +
"weaid='" + weaid + '\'' +
", days='" + days + '\'' +
", week='" + week + '\'' +
", cityno='" + cityno + '\'' +
", citynm='" + citynm + '\'' +
", cityid='" + cityid + '\'' +
", temperature='" + temperature + '\'' +
", temperature_curr='" + temperature_curr + '\'' +
", humidity='" + humidity + '\'' +
", aqi='" + aqi + '\'' +
", weather='" + weather + '\'' +
", weather_curr='" + weather_curr + '\'' +
", weather_icon='" + weather_icon + '\'' +
", weather_icon1='" + weather_icon1 + '\'' +
", wind='" + wind + '\'' +
", winp='" + winp + '\'' +
", temp_high='" + temp_high + '\'' +
", temp_low='" + temp_low + '\'' +
", temp_curr='" + temp_curr + '\'' +
", humi_high='" + humi_high + '\'' +
", humi_low='" + humi_low + '\'' +
", weatid='" + weatid + '\'' +
", weatid1='" + weatid1 + '\'' +
", windid='" + windid + '\'' +
", winpid='" + winpid + '\'' +
", weather_iconid='" + weather_iconid + '\'' +
'}';
}
}
@Override
public String toString() {
return "WeatherBean{" +
"success='" + success + '\'' +
", result=" + result +
'}';
}
}
5、activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/btn_weather"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="加載天氣信息" />
<TextView
android:id="@+id/tv_msg1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/btn_weather" />
<View
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_below="@+id/tv_msg1"
android:layout_height="1dp"
android:background="@android:color/holo_red_light"/>
<TextView
android:id="@+id/tv_msg2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/view" />
</RelativeLayout>
6、MainActivity.class
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.alibaba.fastjson.JSON;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn_weather;
private TextView tv_msg1;
private TextView tv_msg2;
private String url = "http://api.k780.com:88/?weaid=hangzhou&app=weather.today&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_weather = findViewById(R.id.btn_weather);
btn_weather.setOnClickListener(this);
tv_msg1 = findViewById(R.id.tv_msg1);
tv_msg2 = findViewById(R.id.tv_msg2);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_weather:
Observable.create(new ObservableOnSubscribe<Response>() {
@Override
public void subscribe(ObservableEmitter<Response> emitter) throws Exception {
//發(fā)送天氣信息請(qǐng)求
Request.Builder builder = new Request.Builder()
.url(url)
.get();
Request request = builder.build();
Call call = new OkHttpClient().newCall(request);
Response response = call.execute();
//被觀察者將返回的天氣信息發(fā)射出去
emitter.onNext(response);
}
})
.subscribeOn(Schedulers.io())//將被觀察者線程切換到io操作線程進(jìn)行網(wǎng)絡(luò)請(qǐng)求操作
.observeOn(AndroidSchedulers.mainThread())//指定map操作符線程為Android主線程(Ui線程)
.map(new Function<Response, WeatherBean>() { //對(duì)被觀察者發(fā)送的事件通過(guò)Function函數(shù)進(jìn)行變化
@Override
public WeatherBean apply(Response response) throws Exception {
if (response.isSuccessful()) {
ResponseBody body = response.body();
if (body != null) {
//將請(qǐng)求返回Json數(shù)據(jù)轉(zhuǎn)換為WeatherBean對(duì)象
WeatherBean weatherBean = JSON.parseObject(body.string(), WeatherBean.class);
tv_msg1.setText(weatherBean.toString());
return weatherBean;
}
}
return null;
}
})
.observeOn(Schedulers.newThread())//指定doOnNext()方法的工作線程為常規(guī)新線程,執(zhí)行耗時(shí)操作
.doOnNext(new Consumer<WeatherBean>() { //讓訂閱者在接收到數(shù)據(jù)前進(jìn)行一些事情處理的操作符
@Override
public void accept(WeatherBean weatherBean) throws Exception {
//加個(gè)延時(shí),模擬耗時(shí)操作,比如將網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)進(jìn)行數(shù)據(jù)庫(kù)存儲(chǔ)或文件存儲(chǔ)
Thread.sleep(1000);
}
})
.observeOn(AndroidSchedulers.mainThread())//指定觀察者接收線程為Android主線程(Ui線程)
.subscribe(new Consumer<WeatherBean>() { //觀察者訂閱被觀察者事件
@Override
public void accept(WeatherBean weatherBean) throws Exception {
tv_msg2.setText("日期:" + weatherBean.getResult().getDays() + "\n"
+ "城市:" + weatherBean.getResult().getCitynm() + "\n"
+ "最高和最低溫度:" + weatherBean.getResult().getTemperature() + "\n"
+ "當(dāng)前溫度:" + weatherBean.getResult().getTemperature_curr() + "\n"
+ "天氣:" + weatherBean.getResult().getWeather());
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
tv_msg2.setText("失?。? + throwable.getMessage());
}
});
break;
}
}
}
7、運(yùn)行效果

先讀取緩存,如果緩存沒(méi)數(shù)據(jù)再通過(guò)網(wǎng)絡(luò)請(qǐng)求獲取數(shù)據(jù)后更新UI
- 在實(shí)際應(yīng)用中,很多時(shí)候都需要我們先讀取緩存的數(shù)據(jù),如果緩存沒(méi)有數(shù)據(jù),再通過(guò)網(wǎng)絡(luò)請(qǐng)求獲取,隨后在主線程更新我們的 UI。concat 操作符簡(jiǎn)直就是為我們這種需求量身定做。concat 可以做到不交錯(cuò)的發(fā)射兩個(gè)甚至多個(gè) Observable 的發(fā)射事件,并且只有前一個(gè) Observable 終止( onComplete() ) 后才會(huì)定義下一個(gè)Observable。利用這個(gè)特性,我們就可以先讀取緩存數(shù)據(jù),倘若獲取到的緩存數(shù)據(jù)不是我們想要的,再調(diào)用 onComplete() 以執(zhí)行獲取網(wǎng)絡(luò)數(shù)據(jù)的 Observable,如果緩存數(shù)據(jù)能應(yīng)我們所需,則直接調(diào)用 onNext() ,防止過(guò)度的網(wǎng)絡(luò)請(qǐng)求,浪費(fèi)用戶的流量。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn_weather;
private TextView tv_msg1;
private TextView tv_msg2;
private String url = "http://api.k780.com:88/?weaid=hangzhou&app=weather.today&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json";
private WeatherBean cacheWeatherData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_weather = findViewById(R.id.btn_weather);
btn_weather.setOnClickListener(this);
tv_msg1 = findViewById(R.id.tv_msg1);
tv_msg2 = findViewById(R.id.tv_msg2);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_weather:
//讀取緩存數(shù)據(jù)被觀察者
Observable<WeatherBean> cache = Observable.create(new ObservableOnSubscribe<WeatherBean>() {
@Override
public void subscribe(ObservableEmitter<WeatherBean> emitter) throws Exception {
if (cacheWeatherData != null) { //如果緩存不為空,直接通過(guò)緩存更新UI
tv_msg1.setText("直接通過(guò)緩存數(shù)據(jù)更新UI");
//緩存不為空直接調(diào)用onNext()發(fā)射數(shù)據(jù)給觀察者更新UI
emitter.onNext(cacheWeatherData);
} else {
// 在操作符 concat 中,只有調(diào)用 onComplete 之后才會(huì)執(zhí)行下一個(gè) Observable,這里是下面的network被觀察者
emitter.onComplete();
}
}
});
//通過(guò)網(wǎng)絡(luò)請(qǐng)求獲取數(shù)據(jù)被觀察者
Observable<WeatherBean> network = Observable.create(new ObservableOnSubscribe<Response>() {
@Override
public void subscribe(ObservableEmitter<Response> emitter) throws Exception {
//發(fā)送天氣信息請(qǐng)求
Request.Builder builder = new Request.Builder()
.url(url)
.get();
Request request = builder.build();
Call call = new OkHttpClient().newCall(request);
Response response = call.execute();
//被觀察者將返回的天氣信息發(fā)射出去
emitter.onNext(response);
}
})
.subscribeOn(Schedulers.io())//將被觀察者線程切換到io操作線程進(jìn)行網(wǎng)絡(luò)請(qǐng)求操作
.observeOn(AndroidSchedulers.mainThread())//指定map操作符線程為Android主線程(Ui線程)
.map(new Function<Response, WeatherBean>() { //對(duì)被觀察者發(fā)送的事件通過(guò)Function函數(shù)進(jìn)行變化
@Override
public WeatherBean apply(Response response) throws Exception {
if (response.isSuccessful()) {
ResponseBody body = response.body();
if (body != null) {
//將請(qǐng)求返回Json數(shù)據(jù)轉(zhuǎn)換為WeatherBean對(duì)象
WeatherBean weatherBean = JSON.parseObject(body.string(), WeatherBean.class);
tv_msg1.setText(weatherBean.toString());
return weatherBean;
}
}
return null;
}
})
.observeOn(Schedulers.newThread())//指定doOnNext()方法的工作線程為常規(guī)新線程,執(zhí)行耗時(shí)操作
.doOnNext(new Consumer<WeatherBean>() { //讓訂閱者在接收到數(shù)據(jù)前進(jìn)行一些事情處理的操作符
@Override
public void accept(WeatherBean weatherBean) throws Exception {
//加個(gè)延時(shí),模擬耗時(shí)操作,比如將網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)進(jìn)行數(shù)據(jù)庫(kù)存儲(chǔ)或文件存儲(chǔ)
Thread.sleep(1000);
cacheWeatherData = weatherBean;
}
});
// 兩個(gè) Observable 的泛型應(yīng)當(dāng)保持一致
Observable.concat(cache, network)
.observeOn(AndroidSchedulers.mainThread())//指定觀察者接收線程為Android主線程(Ui線程)
.subscribe(new Consumer<WeatherBean>() { //觀察者訂閱被觀察者事件
@Override
public void accept(WeatherBean weatherBean) throws Exception {
tv_msg2.setText("日期:" + weatherBean.getResult().getDays() + "\n"
+ "城市:" + weatherBean.getResult().getCitynm() + "\n"
+ "最高和最低溫度:" + weatherBean.getResult().getTemperature() + "\n"
+ "當(dāng)前溫度:" + weatherBean.getResult().getTemperature_curr() + "\n"
+ "天氣:" + weatherBean.getResult().getWeather());
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
tv_msg2.setText("失?。? + throwable.getMessage());
}
});
break;
}
}
}
- 有時(shí)候我們的緩存可能還會(huì)分為 memory 和 disk ,實(shí)際上都差不多,無(wú)非是多寫(xiě)點(diǎn) Observable ,然后通過(guò) concat 合并即可。
-
效果圖:RxJava實(shí)例2.gif
多個(gè)網(wǎng)絡(luò)請(qǐng)求依次依賴
- 這里就還是拿上面那個(gè)請(qǐng)求天氣數(shù)據(jù)例子來(lái)做文章。天氣數(shù)據(jù)里面有個(gè)weather_icon數(shù)據(jù)是天氣狀況圖片的url,當(dāng)天氣數(shù)據(jù)請(qǐng)求下來(lái)之后得到圖片url,我們還需要依賴這個(gè)url繼續(xù)去請(qǐng)求得到圖片顯示出來(lái)。我們需要用操作符來(lái)實(shí)現(xiàn)呢,其實(shí)就用我們最開(kāi)始用過(guò)的map操作符就可以實(shí)現(xiàn)。
- 類似代碼我就不貼出了,僅將點(diǎn)擊事件的代碼貼出如下,還有就是加了一個(gè)顯示圖片的ImageView控件iv_weather。
Observable.create(new ObservableOnSubscribe<Response>() {
@Override
public void subscribe(ObservableEmitter<Response> emitter) throws Exception {
//發(fā)送天氣信息請(qǐng)求
Request.Builder builder = new Request.Builder()
.url(url)
.get();
Request request = builder.build();
Call call = new OkHttpClient().newCall(request);
Response response = call.execute();
//被觀察者將返回的天氣信息發(fā)射出去
emitter.onNext(response);
}
})
.subscribeOn(Schedulers.io())//將被觀察者線程切換到io操作線程進(jìn)行網(wǎng)絡(luò)請(qǐng)求操作
.map(new Function<Response, Bitmap>() {
@Override
public Bitmap apply(Response response) throws Exception {
if (response.isSuccessful()) {
ResponseBody body = response.body();
if (body != null) {
//將請(qǐng)求返回Json數(shù)據(jù)轉(zhuǎn)換為WeatherBean對(duì)象
WeatherBean weatherBean = JSON.parseObject(body.string(), WeatherBean.class);
//根據(jù)天氣圖片url再進(jìn)行一次網(wǎng)絡(luò)請(qǐng)求得到圖片
Request.Builder builder = new Request.Builder()
.url(weatherBean.getResult().getWeather_icon())
.get();
Request request = builder.build();
Call call = new OkHttpClient().newCall(request);
Response imgResponse = call.execute();
InputStream imgInputStream = imgResponse.body().byteStream();
Bitmap bitmap = BitmapFactory.decodeStream(imgInputStream);
if (bitmap != null) {
return bitmap;
}
}
}
return null;
}
})
.observeOn(AndroidSchedulers.mainThread())//指定觀察者接收線程為Android主線程(Ui線程)
.subscribe(new Consumer<Bitmap>() {
@Override
public void accept(Bitmap bitmap) throws Exception {
iv_weather.setImageBitmap(bitmap);
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
tv_msg2.setText("失?。? + throwable.getMessage());
}
});
-
效果圖
RxJava實(shí)例3.gif
結(jié)合多個(gè)接口的數(shù)據(jù)更新UI
- 依舊是上面那個(gè)天氣數(shù)據(jù)請(qǐng)求的例子,比如我要同時(shí)請(qǐng)求我家和我工作地方的天氣顯示在頁(yè)面上,這時(shí)就要用到zip操作符了,zip 操作符可以將多個(gè) Observable 的數(shù)據(jù)結(jié)合為一個(gè)數(shù)據(jù)源再發(fā)射出去。
//請(qǐng)求工作處天氣數(shù)據(jù)
Observable<WeatherBean> work = Observable.create(new ObservableOnSubscribe<Response>() {
@Override
public void subscribe(ObservableEmitter<Response> emitter) throws Exception {
//發(fā)送天氣信息請(qǐng)求
Request.Builder builder = new Request.Builder()
.url(url)
.get();
Request request = builder.build();
Call call = new OkHttpClient().newCall(request);
Response response = call.execute();
//被觀察者將返回的天氣信息發(fā)射出去
emitter.onNext(response);
}
})
.subscribeOn(Schedulers.io())//將被觀察者線程切換到io操作線程進(jìn)行網(wǎng)絡(luò)請(qǐng)求操作
.observeOn(AndroidSchedulers.mainThread())//指定map操作符線程為Android主線程(Ui線程)
.map(new Function<Response, WeatherBean>() { //對(duì)被觀察者發(fā)送的事件通過(guò)Function函數(shù)進(jìn)行變化
@Override
public WeatherBean apply(Response response) throws Exception {
if (response.isSuccessful()) {
ResponseBody body = response.body();
if (body != null) {
//將請(qǐng)求返回Json數(shù)據(jù)轉(zhuǎn)換為WeatherBean對(duì)象
WeatherBean weatherBean = JSON.parseObject(body.string(), WeatherBean.class);
tv_msg1.setText(weatherBean.toString());
return weatherBean;
}
}
return null;
}
});
//請(qǐng)求家里天氣數(shù)據(jù)
Observable<String> home = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
//發(fā)送天氣信息請(qǐng)求
Request.Builder builder = new Request.Builder()
.url("http://api.k780.com:88/?weaid=ganzhou&app=weather.today&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json")
.get();
Request request = builder.build();
Call call = new OkHttpClient().newCall(request);
Response response = call.execute();
//被觀察者將返回的天氣信息發(fā)射出去
if (response.isSuccessful()) {
ResponseBody body = response.body();
if (body != null) {
emitter.onNext(body.string());
}
}
}
}).subscribeOn(Schedulers.io());//將被觀察者線程切換到io操作線程進(jìn)行網(wǎng)絡(luò)請(qǐng)求操作
//結(jié)合多個(gè)接口的數(shù)據(jù)更新UI
Observable.zip(work, home, new BiFunction<WeatherBean, String, String>() {
@Override
public String apply(WeatherBean weatherBean, String responseString) throws Exception {
//合并兩地天氣
String workWeather = weatherBean.getResult().getWeather();
int weatherDataStartIndex = responseString.indexOf("\"weather\":\"") + "\"weather\":\"".length();
int weatherDataEndIndex = responseString.indexOf("\",", weatherDataStartIndex);
String homeWeather = responseString.substring(weatherDataStartIndex, weatherDataEndIndex);
return "工作地方天氣:" + workWeather + "\n家里天氣:" + homeWeather;
}
})
.observeOn(AndroidSchedulers.mainThread()) //切換到Ui線程
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
tv_msg2.setText(s);
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
tv_msg2.setText("失?。? + throwable.getMessage());
}
});
間隔任務(wù)實(shí)現(xiàn)心跳
- 想必即時(shí)通訊等需要輪訓(xùn)的任務(wù)在如今的 APP 中已是很常見(jiàn),而 RxJava 的 interval 操作符可謂完美地解決了我們的疑惑。
private Disposable mDisposable;
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_weather:
mDisposable = Flowable.interval(1, TimeUnit.SECONDS) //interval間隔操作符,自帶Long類型返回值從0開(kāi)始每執(zhí)行間隔操作一次自加一
.observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<Long>() {
@Override
public void accept(@NonNull Long aLong) throws Exception { //Long aLong為interval自帶的返回值
tv_msg2.append("心跳次數(shù):" + aLong + "\n");
}
});
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mDisposable != null) { //頁(yè)面銷毀時(shí)記得要停止心跳
mDisposable.dispose();
}
}
-
效果圖RxJava實(shí)例4.gif
結(jié)束語(yǔ)
實(shí)例就暫時(shí)先告一段落了,雖然有些實(shí)例有些牽強(qiáng),但是對(duì)RxJava有個(gè)大概的了解完全夠了。還有一點(diǎn)提下就是現(xiàn)在RxJava現(xiàn)在基本都是結(jié)合Retrofit來(lái)一起進(jìn)行網(wǎng)絡(luò)請(qǐng)求,但是我們這里結(jié)合的是OkHttp,一是我認(rèn)為這樣簡(jiǎn)單點(diǎn)更便于理解,二是因?yàn)槭荝etrofit提供了和RxJava一起使用的支持,所有這部分內(nèi)容放到講Retrofit時(shí)會(huì)更合適。



