RxJava 2.x上篇(具體用法)

  • 前言
    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)求

  1. 通過(guò) Observable.create() 方法創(chuàng)建被觀察者,調(diào)用 OkHttp 進(jìn)行網(wǎng)絡(luò)請(qǐng)求;
  2. 通過(guò) map 操作符結(jié)合FastJson對(duì)請(qǐng)求結(jié)果解析,將 Response 轉(zhuǎn)換為 bean 類;
  3. 通過(guò) doOnNext() 方法,進(jìn)行一些其它操作;
  4. 調(diào)度線程,在子線程中進(jìn)行耗時(shí)操作任務(wù),在主線程中更新 UI ;
  5. 觀察者通過(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)行效果

RxJava實(shí)例1.gif

先讀取緩存,如果緩存沒(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ì)更合適。

感謝

這可能是最好的 RxJava 2.x 入門教程(五)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,323評(píng)論 25 708
  • 用兩張圖告訴你,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 14,096評(píng)論 2 59
  • 引入依賴: implementation 'io.reactivex.rxjava2:rxandroid:2.0....
    為夢(mèng)想戰(zhàn)斗閱讀 1,432評(píng)論 0 0
  • 本篇文章介主要紹RxJava中操作符是以函數(shù)作為基本單位,與響應(yīng)式編程作為結(jié)合使用的,對(duì)什么是操作、操作符都有哪些...
    嘎啦果安卓獸閱讀 2,994評(píng)論 0 10
  • “一個(gè)人一輩子最幸福的事情,莫過(guò)于做一件自己愛(ài)做的事情,并且還可以通過(guò)這件事養(yǎng)活自己和獲得榮譽(yù)?!被刍劾蠋煈?yīng)該就屬...
    阿雪姑釀閱讀 1,084評(píng)論 0 2

友情鏈接更多精彩內(nèi)容