在Kotlin中实现简洁优雅的RxBus

最近用Kotlin写代码比较多,写的多了真的越来越来喜欢这门语言。作为一门现代化的语言,Kotlin对比Java提供了简介的语法,更强大的lambda支持,属性扩展委托等。作为一个Android开发者的我来言,Kotlin over Java。

组件之间的通信经常用到,用传统的接口方式也比较繁琐。而且目前的项目基本也都使用了RxJava,所以索性写个RxBus来实现好了。可能有人会说,我直接用EventBus好了呀,github上一万多个Star呢!


沉默......

我想说,你喜欢就好。EventBus确实更加完整,但是如果有现成的我个人是不喜欢用第三方的。

1.实现RxBus

object RxBus {
    private val TAG = javaClass.simpleName

    /**
     * 用于保存RxBus事件的所有订阅,并在需要时正确的取消订阅。
     */
    private val disposablesMap: HashMap by lazy {
        HashMap()
    }

    /**
     * 避免直接使用此属性,因为它仅在内联函数中使用而暴露
     */
    val rxBus = ReplaySubject.create().toSerialized()


    /**
     * 向RxBus发送一个事件,这个事件可以来自任意一个线程
     */
    fun send(event: Any) {
        rxBus.onNext(event)
    }

    /**
     * 订阅特定类型T的事件。可以从任何线程调用
     */
    inline fun  observe(): Observable {
        return rxBus.ofType(T::class.java)
    }

    /**
     * 从RxBus事件中取消注册订阅者
     * 调用订阅的取消订阅方法
     */
    fun unRegister(disposable: Any) {
        val compositeDisposable = disposablesMap[disposable]
        if (compositeDisposable == null) {
            Log.w(TAG, "Trying to unregister subscriber that wasn't registered")
        } else {
            compositeDisposable.clear()
            disposablesMap.remove(disposable)
        }
    }

    /**
     * internal修饰符 只有在相同模块中才能使用
     */
    internal fun register(disposable: Any, composite: Disposable) {
        var compositeDisposable = disposablesMap[disposable]
        if (compositeDisposable == null) {
            compositeDisposable = CompositeDisposable()
        }
        compositeDisposable.add(composite)
        disposablesMap[disposable] = compositeDisposable
    }
}

/**
 * 注册订阅以便以后正确注销它以避免内存泄漏
 * @param disposable 拥有此订阅的订阅对象
 */
fun Disposable.registerInBus(disposable: Any) {
    RxBus.register(disposable, this)
}

是的,您没有看错。这样就实现了一个RxBus,主要还是在disposable上动手脚。
我们用CompositeDisposable来管理disposable。用HashMap保存事件所有的订阅,当RxBus发送事件时,CompositeDisposable会把disposable添加到容器中,在接收事件的地方进行订阅处理逻辑。当不再需要的时候,CompositeDisposable就会调用clear()方法清除所有订阅,防止内存泄露。
这么讲可能有点含糊,没关系下面我写个实例就很容易理解了。

2.RxBus实例

1)新建一个事件Event类
当然我这里是为了规范便于理解起见,所以一律以xxxEvent的方式命名

class UserEvent(var user: User)

data class User(var name: String, var age: Int)

在构造里只写了个简单的User实体类,具体可以结合业务做改变

2)发送事件

class OneActivity : AppCompatActivity() {

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

        initView()
        initObserve()
    }

    private fun initView() {
        val user = User("小明", 15)

        mBtnActivity.setOnClickListener {
            RxBus.send(UserEvent(user))
            startActivity()
        }

        mBtnFragment.setOnClickListener {
            startActivity()
        }
    }
}

很简单,一行代码RxBus.send(UserEvent(user))搞定

3)接收事件

class TwoActivity : AppCompatActivity() {

    private lateinit var mUserList: MutableList

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

        initObserve()
    }

    private fun initObserve() {
        RxBus.observe()
                .subscribe { t: UserEvent? ->
                    kotlin.run {
                        mContent.text = "name:${t?.user?.name} age:${t?.user?.age}"
                    }
                }
                .registerInBus(this)
    }

    override fun onDestroy() {
        super.onDestroy()
        RxBus.unRegister(this)
    }
}

在TwoActivity中接收事件来更新界面,t?.user?.name对象后面带个?是Kotlin的预判空指针特性,可以提前提醒开发者预防空指针,可以说是十分贴心。

4)解除注册
注意最后不要忘了,在Activity/Fragment的onDestroy()中解除注册,防止内存泄露

override fun onDestroy() {
        super.onDestroy()
        RxBus.unRegister(this)
}

怕大家一遍不过瘾,所以再来一个发送List事件的例子:TwoActivity回发事件给OneActivity。代码比较简单,所以一并奉上了。

class UserListEvent(var users:MutableList)
class TwoActivity : AppCompatActivity() {

    private lateinit var mUserList: MutableList

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

        initView()
        initObserve()
    }

    private fun initView() {
        mUserList = mutableListOf()
        mUserList.add(User("小白", 11))
        mUserList.add(User("小红", 12))
        mUserList.add(User("小黑", 13))
        mUserList.add(User("小绿", 14))
        mBtnReturn.setOnClickListener {
            RxBus.send(UserListEvent(mUserList))
            finish()
        }
    }

    private fun initObserve() {
        RxBus.observe()
                .subscribe { t: UserEvent? ->
                    kotlin.run {
                        mContent.text = "name:${t?.user?.name} age:${t?.user?.age}"
                    }
                }
                .registerInBus(this)
    }

    override fun onDestroy() {
        super.onDestroy()
        RxBus.unRegister(this)
    }
}
class OneActivity : AppCompatActivity() {

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

        initView()
        initObserve()
    }

    private fun initView() {
        val user = User("小明", 15)

        mBtnActivity.setOnClickListener {
            RxBus.send(UserEvent(user))
            startActivity()
        }

        mBtnFragment.setOnClickListener {
            startActivity()
        }
    }

    private fun initObserve() {
        RxBus.observe()
                .subscribe { t: UserListEvent? ->
                    kotlin.run {
                        mContent.text=t?.users?.toString()
                    }
                }.registerInBus(this)
    }

    override fun onDestroy() {
        super.onDestroy()
        RxBus.unRegister(this)
    }

}

还有Fragment之间的通信,代码也是大同小异的,所以和效果图一起展示了。具体的可以到文章末尾的github地址看。

最后附上效果演示图

项目地址

https://github.com/weibindev/Kotlin_RxBus

参考文章

rxjava2的disposable
https://github.com/Dimezis/RxBus

你可能感兴趣的:(在Kotlin中实现简洁优雅的RxBus)