美文网首页
在Kotlin中实现简洁优雅的RxBus

在Kotlin中实现简洁优雅的RxBus

作者: Vico君 | 来源:发表于2018-10-18 22:14 被阅读269次

    最近用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<Any, CompositeDisposable?> by lazy {
            HashMap<Any, CompositeDisposable?>()
        }
    
        /**
         * 避免直接使用此属性,因为它仅在内联函数中使用而暴露
         */
        val rxBus = ReplaySubject.create<Any>().toSerialized()
    
    
        /**
         * 向RxBus发送一个事件,这个事件可以来自任意一个线程
         */
        fun send(event: Any) {
            rxBus.onNext(event)
        }
    
        /**
         * 订阅特定类型T的事件。可以从任何线程调用
         */
        inline fun <reified T : Any> observe(): Observable<T> {
            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<TwoActivity>()
            }
    
            mBtnFragment.setOnClickListener {
                startActivity<ThreeActivity>()
            }
        }
    }
    

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

    3)接收事件

    class TwoActivity : AppCompatActivity() {
    
        private lateinit var mUserList: MutableList<User>
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_two)
    
            initObserve()
        }
    
        private fun initObserve() {
            RxBus.observe<UserEvent>()
                    .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<User>)
    
    class TwoActivity : AppCompatActivity() {
    
        private lateinit var mUserList: MutableList<User>
    
        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<UserEvent>()
                    .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<TwoActivity>()
            }
    
            mBtnFragment.setOnClickListener {
                startActivity<ThreeActivity>()
            }
        }
    
        private fun initObserve() {
            RxBus.observe<UserListEvent>()
                    .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

          本文链接:https://www.haomeiwen.com/subject/ibeqzftx.html