本文不分析操作符的使用方法,主要分析interval轮询中如何来停止。
最近在项目中使用RxJava,RxAndroid;主要运用于网络请求,但是项目中有用到定时任务,每隔20s去更新数据,因此想到RxJava中有定时器操作符,再加上已经引入RxJava,链式请求就完成了,详见代码:
Observable.interval(0, 20, TimeUnit.SECONDS)
.doOnSubscribe {
mDisposable = it
}
.flatMap {
return@flatMap DataUtils.API_SERVICE.getQrCode(userId)
}
.map {
val body = it.string()
val str = body.substring(body.indexOf(",") + 1)
val decodedString = Base64.decode(str, Base64.DEFAULT)
return@map BitmapFactory.decodeByteArray(decodedString, 0, decodedString.size)
}
.compose(ThreadFromUtils.defaultSchedulers())
.subscribe({
dismissProgressDialog()
qr_code.setImageBitmap(it)
}, {
dismissProgressDialog()
var msg = when (it) {
is SocketTimeoutException -> "网络连接超时!"
is ConnectException -> "连接不上服务器,请检查网络链接!"
is IOException -> "流连接意外结束,请稍候重试!"
is HttpException -> "网络出现异常,请稍候重试!"
is JsonSyntaxException -> "数据解析出现错误!"
else -> it.localizedMessage
}
if (msg.isNullOrEmpty()) {
msg = "出现错误,请稍候重试!"
}
showErrorToast(msg)
})
(竟然么有Kotlin选项,将就看看吧。)链式请求也在项目中运用很多,这里用到flatmap和map:flatmap主要返回获取二维码请求->然后在map中生成bitmap->最后展示。这种方法看着舒服,但是也有问题:当接收到error的时候,定时器就会退出。因此不得不改变写法,详见代码:
Observable.interval(0, 20, TimeUnit.SECONDS)
.doOnSubscribe {
mDisposable = it
}
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
refreshQrCode()
}
就是把获取二维码代码的请求在定时器每发送一次onNext中去执行,这样就解决了当接收到error的时候,定时器就会退出的问题。但是测试提出Bug说,离开这个页面还在刷新二维码数据。因此不得不在onPause里面把mDisposable.cancel()取消掉,如果可以也就万事大吉了;不想这样不仅没有用,还引出一个Bug,心里那个憋屈吖,只能打碎牙齿往肚子里咽。Bug截图如图示:
经细看是因为刷新二维码都会有一个弹框等待,由于Activity已经销毁,所以Dialog add window 失败。 想着先骗过测试吧,于是在获取二维码数据时,增加了一个判断,if(activity != null && !activity!!.isFinishing)时去获取,否则不获取二维码数据。
这样只是应付测试,自己还要找结局方案,于是搜索Observable interval stop,在StackOverflow是找到解决方案,最后修改为,详见代码:
Observable.interval(0, 20, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
.takeWhile {
!mStop
}
.subscribe {
refreshQrCode()
}
mStop是是否停止标志,在onResume()中赋值为false,在onPause()中赋值为true,然后测试没有再打印日志,应该是停止了,再次进入时又重新打印日志。至此停止定时任务以及延申的问题都解决了,在此记录一下,希望对采坑的朋友有帮助。