JAVA线程池的血案_漫画:一个Bug引发的RxJava血案

原标题:漫画:一个Bug引发的RxJava血案

来自公众号:码个蛋

原文链接:https://five.agency/debugging-rxjava

4ab4d82ef66db568740031cdf291ee14.png

b1e21b88226f16d6c920deda297bfdb5.png

classMainActivity: AppCompatActivity{

private val refreshProcessor = PublishProcessor.create

override fun onCreate( savedInstanceState:Bundle?) {

refreshButton.setOnClickListener {

refreshProcessor.onNext(Unit)

}

refreshProcessor

.flatMapSingle(networkRequest::fetchData)

.subscribeOn(backgroundScheduler)

.observeOn(mainScheduler)

.subscribe(view::render)

}

}

5f2b21999f74410796abdf4fd56a6639.png

8bea9705b05c8dfa229156ef73dbc384.png

de5eba9b44e204f83186248f49e366e7.png

不够的。您的Rx调用链将在调用onNext的线程上执行,而且在我们的例子中,这是主线程,因此onClickListeners是在主线程上得到通知。

最糟糕的是,在大多数情况下,您的应用程序不会像我们的Demo中那样崩溃,但是主逻辑将在主线程上执行,这可能会导致UI上的丢帧和糟糕的用户体验。

如何解决问题呢?

这个问题没有通用的解决办法。开发人员需要评估这些问题中的每一个,并找到针对特定问题的最佳解决方案。我们需要意识到这一点,但又不得不调试应用程序中的每一种可能的Rx调用链来找出有问题的那个。

我们希望我们的应用程序在发生类似的事情时“抱怨”一下。我的意思是:它能打断DEBUG构建并将日志记录到RELEASE构建中。

在简单思考如何实现后,可以得出结论:如果我们想切换到主线程,这意味着我们已经不想再进入主线程了。

这很容易用.compose操作符实现,在切换到主线程之前,我们先用它检查当前线程是否是主线程。即使这样做可行,我们也不希望有任何额外的操作符开销。

73d6cfc506d8a5d58bec9fb693a64adf.png

6738db78bf1cb4e9587bd81c1083cf81.png

classOnRescheduleNotifyMainScheduler:Scheduler {

privateval mainScheduler = AndroidSchedulers.mainThread

override fun createWorker = object : Worker {

privateval worker = mainScheduler.createWorker

override fun schedule(run: Runnable, delay: Long, unit: TimeUnit): Disposable {

if(Looper.myLooper == Looper.getMainLooper) {

logOrError

}

returnworker.schedule(run, delay, unit)

}

override fun dispose = worker.dispose

override fun isDisposed = worker.isDisposed

}

}

be0f9b8efa9cc78a10206b11a66b0de0.png

c009d3e68932859512a1b360e941a29c.png

d5b59d886ec268ca4daa7a6a46b11117.png

publishProcessor

.filter( this::isValid)

.map( this::toViewModel)

.doOnNext( this::log)

.observeOn(mainScheduler)

.subscribe( view::render)

通过调试我们可以发现:当调用.subscribe时,订阅过程的启动,将包括三个步骤:

订阅上游流

通知下游onsubscribed

向上游索取item

就像下面这样:

14e40804060f0ffef2164c93c4886ea8.png

我们注意到,当.observeOn操作符请求数据时,它在提供的调度程序(即Demo中的onRescheduleNotifyMainscheduler)上调度一个任务,但从当前线程调度一个任务,该线程也是主线程,因为RxJava链中没有任何.subscribeOn(backgroundscheduler)。

2d3beb570ae36701e35be465f76f71f0.png

Weaddedthe.subscribeOnoperatortothemiddleofourchainandstarteddebuggingagain.

publishProcessor

.filter( this::isValid)

.map( this::toViewModel)

.subscribeOn(backgroundScheduler)

.doOnNext( this::log)

.observeOn(mainScheduler)

.subscribe( view::render)

9d2c062a7f8b5793b499f145a40c4359.png

0179223f50eb00f2967a85cf3e6c3de9.png

subscribeOn 运算符只将订阅进程切换到所需的线程,但这并不意味着项目将在该线程上发出。我们已经说过订阅过程由三个步骤组成,.subscribeOn操作符将这三个步骤切换到指定的线程。它的作用就像是链中的最后一环,当有人订阅它时,它会立即在下游调用 onSubscribed。当下游向它请求数据时,它会订阅上游,并且会在提供的线程上调用subscribe方法。

ebed5651de8f4ea1d882287e0732f332.png

总结

3526184ccc8471711aaee2043b32faab.png

9b40cfae6993f1f3db3d6347f6b98a59.png

●编号571,输入编号直达本文返回搜狐,查看更多

责任编辑:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值