RxJava常用的操作

242 阅读4分钟

Rxjava

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

函数式编程

异步操作

Android

  • AsyncTask
  • Handler
  • RxJava

RxJava

通过扩展的观察者模式来实现

4个角色

Observable 被观察者 发射数据

Observer 观察者

Subscriber 观察者 实现回调

Subject 观察者 + 被观察者

通过subscribe实现订阅关系

subscribeOn() 执行线程, 用于指定Observable在哪个线程上面运行,一般指定子线程,如io线程Schedules.io(),kotlin省略写法为io()

observerOn() 回调线程,用于指定Observer发射出去的数据在哪个线程,一般指定主线程AndroidSchedules.MainThread()

场景:各种接口请求回调

package com.example.recycleviewdemo

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import rx.Observable
import rx.Scheduler
import rx.Subscriber
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import rx.schedulers.Schedulers.io

class MainActivity : AppCompatActivity() {

    companion object {
        const val TAG = "RxJava"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        subscriber()
    }

    private fun subscriber() {

        val subscriber = object : Subscriber<String>() {
            override fun onNext(t: String?) {
                Log.d(TAG, "onNext$t")
            }

            override fun onCompleted() {
                Log.d(TAG, "onCompleted")
            }

            override fun onError(e: Throwable?) {
                Log.d(TAG, "onError")
            }

            override fun onStart() {
                Log.d(TAG, "onStart")
            }
        }

        val observable = Observable.create(Observable.OnSubscribe<String> {
            subscriber.onNext("Fage")
            subscriber.onNext("HaiLiting")
            subscriber.onCompleted()
        }).subscribeOn(io())
                .observeOn(AndroidSchedulers.mainThread())

        observable.subscribe(subscriber)
    }
}

操作符

固定时间间隔发射数据 场景:接口轮询

/**
     * 间隔回调
     */
    private fun intervalTest() {

        Observable.interval(3, TimeUnit.SECONDS)
                .subscribe {
                    runOnUiThread {
                        Log.d(TAG, "Result$it")
                        Log.d(TAG, Thread.currentThread().name)
                    }
                }
    }

创建指定范围的整数序列的Observable,可用来代替For循环 场景:各种需要for循环的操作

/**
     * 整数序列范围循环
     * 可用于代替for循环
     */
    private fun intervalRange() {

        Observable.range(0, 60)
                .subscribe {
                    runOnUiThread {
                        Log.d(TAG, "Result$it")
                    }
                }
    }

flatMap 把一个数据集合的每个元素进行操作,输出一个新的集合

/**
     * 集合转换
     * 给每个元素添加东西
     */
    private fun flatMap() {

        val host = "http://www.baidu.com/"

        val list = ArrayList<String>()
        list.add("1")
        list.add("2")
        list.add("3")
        list.add("4")

        Observable.from(list).flatMap { t ->
            Observable.just(host + t) }
                .cast(String::class.java)
                .subscribe{
                    Log.d(TAG, "Flapmap=$it")
                }
    }

filter 过滤操作符号

/**
     * 过滤数据
     */
    private fun filterTest() {

        for (bean in getData()) {
            Observable.just(bean).filter { bean1 ->
                bean1.age > 26 }.subscribe {
                bean2 ->
                Log.d(TAG, "bean=${bean2.age}") }
        }

    }

组和操作符 场景:多个接口同时发出

Merge 无顺序请求接口

    @Override
    public void getPlaceAndWeatherData(String place) {
        mMainView.showProgress();
        PlaceRepository repository = new PlaceRepository();
        Context context = BaseApplication.getInstance();
        Observable placeObservable = repository.getPlaceList(context);
        Observable weatherObservable =  ServiceManager.getInstance().getApiService().getWeatherInfo(place, Constants.BAIDU_AK);
        Observable.merge(placeObservable, weatherObservable)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Object>() {
                    @Override
                    public void onCompleted() {
                        mMainView.hideProgress();
                    }

                    @Override
                    public void onError(Throwable e) {
                        mLogger.error(e.getMessage(), e);
                        mMainView.hideProgress();
                    }

                    @Override
                    public void onNext(Object obj) {
                        if (obj instanceof List) {
                            mMainView.setupPlaceData((List<Place>) obj);
                        } else if (obj instanceof WeatherResponse) {
                            mMainView.setupWeatherData((WeatherResponse) obj);
                        }
                    }
                });
    }

concat 多个接口同时发出,并且按照顺序返回

    @Override
    public void getPlaceAndWeatherData(String place) {
        mMainView.showProgress();
        PlaceRepository repository = new PlaceRepository();
        Context context = BaseApplication.getInstance();
        Observable placeObservable = repository.getPlaceList(context);
        Observable weatherObservable =  ServiceManager.getInstance().getApiService().getWeatherInfo(place, Constants.BAIDU_AK);
        Observable.concat(placeObservable, weatherObservable)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Object>() {
                    @Override
                    public void onCompleted() {
                        mMainView.hideProgress();
                    }

                    @Override
                    public void onError(Throwable e) {
                        mLogger.error(e.getMessage(), e);
                        mMainView.hideProgress();
                    }

                    @Override
                    public void onNext(Object obj) {
                        if (obj instanceof List) {
                            mMainView.setupPlaceData((List<Place>) obj);
                        } else if (obj instanceof WeatherResponse) {
                            mMainView.setupWeatherData((WeatherResponse) obj);
                        }
                    }
                });
    }

Zip 合并接口 场景:适用于多个接口同时请求,返回的时候合并结果返回

/**
     * RxJava Zip
     * 创建多个观察者
     * zip
     * object : Func2<T1, T2, ... , R>
     * @param T1 第一个的类型
     * @param T2 第二个的类型
     * ...       第N个的类型
     * @param R 合并后的结果类型
     */
    private fun zip() {
        val observable1 = Observable.just(1,2,3)
        val observable2 = Observable.just(3,4,5)

       Observable.zip(observable1, observable2) { 
           t1, t2 -> t1 + t2 
       }.subscribe {
           Log.d(TAG, it.toString())
      	   Log.d(TAG, Thread.currentThread().name)
      }
    }

Android常用场景

RxJava + RxAndroid + Okhttp + Retrofit 进行网络请求

implementation 'io.reactivex:rxjava:1.2.0'
    implementation 'io.reactivex:rxandroid:1.2.1'
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation 'com.squareup.retrofit2:adapter-rxjava:2.9.0'
  • 接口
interface PlaceService {

    @GET("v2/place?token=aioxxxxFsuuj&lang=zh_CN")
    fun searchPlaces(@Query("query") query: String): Observable<PlaceResponse>
}
  • 在Activity中使用
  • 首先写一个BasePresenter主要用来管理RxJava订阅请求
package com.example.recycleviewdemo

import rx.Subscription
import rx.subscriptions.CompositeSubscription

open class BasePresenter {

    private val compositeSubscription = CompositeSubscription()

    fun addSubscription(sub: Subscription) {
        compositeSubscription.add(sub)
    }

    fun unSubscribe() {
        compositeSubscription.unsubscribe()
    }
}
  • 之后写一个BaseActivity,onDestroy方法中,调用解除订阅方法
package com.example.recycleviewdemo

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.orhanobut.logger.AndroidLogAdapter
import com.orhanobut.logger.Logger

abstract class BaseActivity : AppCompatActivity() {

    private var mPresenter: BasePresenter? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        initPresenter()
        initView()
        setContentView(getContentViewId())

        Logger.addLogAdapter(AndroidLogAdapter())
    }

    protected abstract fun initPresenter()
    protected abstract fun initView()
    protected abstract fun getContentViewId(): Int

    fun setPresenter(presenter: BasePresenter) {
        mPresenter = presenter
    }

    override fun onDestroy() {
        super.onDestroy()
        mPresenter?.unSubscribe()
        Logger.t("fage").d("移除请求")
    }
}
  • 接下来写个网络请求管理类
package com.example.recycleviewdemo

import retrofit2.Retrofit
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import rx.Subscriber
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers

class PlacePresenter: BasePresenter() {

    companion object {
        const val TAG = "IpPresenter"
    }

    fun getPlaceInfoFormation() {

        val baseUrl = "https://api.caiyunapp.com/"
        val retrofit = Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .build()
        val placeService = retrofit.create(PlaceService::class.java)
        val subscription = placeService.searchPlaces("杭州")
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Subscriber<PlaceResponse>() {
                override fun onNext(t: PlaceResponse) {
                    Logger.json(TAG, t)
                }

                override fun onCompleted() {
                    Logger.d(TAG,"onCompleted")
                }

                override fun onError(e: Throwable) {
                    Logger.d(TAG,"onError")
                }
            })
        addSubscription(subscription)
    }
}
  • 接下来MainActivity中使用 设置Presenter 并发起请求
class MainActivity : BaseActivity() {

    private val mPresenter: PlacePresenter by lazy {
        PlacePresenter()
    }

    companion object {
        const val TAG = "RxJava"
    }

    override fun getContentViewId(): Int {
        return R.layout.activity_main
    }

    override fun initPresenter() {
        setPresenter(mPresenter)
        mPresenter.getPlaceInfoFormation()
    }
 }
  • 可以发现,当我们退出App的时候成功销毁了请求

使用RxBus跨线程、跨Activity、跨Fragment通信

  • 写一个RxBus的单例
package com.example.rxjavademo.rxbus

import rx.Observable
import rx.subjects.PublishSubject
import rx.subjects.SerializedSubject
import rx.subjects.Subject

/**
 * RxBus Kotlin版本
 */
object RxBusKotlin {
    private var subject: Subject<Any, Any>? = null

    /**
     * RxBus是非线程安全的 这里采用了SerializedSubject保证线程安全
     */
    init {
        subject = SerializedSubject(PublishSubject.create())
    }

    /**
     * 发送事件
     *
     * @param object
     */
    fun post(obj: Any) {
        subject!!.onNext(obj)
    }

    /**
     * 根据类型接收相应类型事件
     * 只会发送指定类型的数据
     * @param eventType
     * @param <T>
     * @return
    </T> */
    fun <T> toObservable(eventType: Class<T>): Observable<*> {
        return subject!!.ofType(eventType)
    }
}
  • 监听
/**
     * Rxbus监听
     */
    private fun rxbus() {
        addSubscription(RxBusKotlin.toObservable(MessageEvent::class.java)
            .subscribe{
                textView.text = (it as MessageEvent).name
            })
    }
  • 消息发送
RxBusKotlin.post(MessageEvent("发哥变了哦"))
  • 注意取消订阅
package com.example.rxjavademo

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.orhanobut.logger.AndroidLogAdapter
import com.orhanobut.logger.Logger
import rx.Subscription
import rx.subscriptions.CompositeSubscription

abstract class BaseActivity : AppCompatActivity() {

    private var mPresenter: BasePresenter? = null
    private var mRxCompositeSubscription: CompositeSubscription? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        mRxCompositeSubscription = CompositeSubscription()

        initPresenter()
        initView()
        setContentView(getContentViewId())

        Logger.addLogAdapter(AndroidLogAdapter())
    }

    protected abstract fun getContentViewId(): Int
    protected abstract fun initPresenter()
    protected abstract fun initView()

    fun setPresenter(presenter: BasePresenter) {
        mPresenter = presenter
    }

    fun addSubscription(sub: Subscription) {
        mRxCompositeSubscription!!.add(sub)
    }

    override fun onDestroy() {
        super.onDestroy()
        mPresenter?.unSubscribe()
        mRxCompositeSubscription?.unsubscribe()
        Logger.t("fage").d("移除请求")
    }
}