使用一个简单的RxKotlin Single,我会收到一个android.view.ViewRootImpl$CalledFromWrongThreadException
异常,或者通过添加.observeOn(AndroidSchedulers.mainThread())
,我会收到一个NetworkOnMainThread
异常。
fun loadStaffCalendar() {
var calendarParser = CalendarParser()
calendarParser.getSingleBearCal()
.subscribeOn(Schedulers.io())
.subscribeBy(
onError ={error("Error loading calendar\n${it.message}")},
onSuccess = { responseBody ->
println("ResponseBody retrieved")
var staffList = calendarParser.parseStringIntoSchedule(responseBody.string())
view.loadToAdapter(staffList)
println(staffList)
}
)
我可以让staffList在控制台中打印,但是当我试图将它加载到View的适配器中时,它崩溃并出现CalledFromWrongThread异常。
这是当我添加.observeOn(AndroidSchedulers.mainThread()):
时的崩溃
io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | android.os.NetworkOnMainThreadException
at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367)
at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:126)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1513)
at com.android.org.conscrypt.Platform.blockGuardOnNetwork(Platform.java:415)
at com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLInputStream.read(ConscryptFileDescriptorSocket.java:527)
at okio.InputStreamSource.read(Okio.kt:102)
在任何地方都不会进行额外的网络呼叫。以下是剩下的:
class CalendarParser : AnkoLogger {
fun getSingleBearCal(): Single<ResponseBody> {
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl("https://www.brownbearsw.com/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
val bearApi: BearApi = retrofit.create(BearApi::class.java)
return bearApi.file
}
fun parseStringIntoSchedule(wholeSchedule: String): ArrayList<StaffModel> {
var dateMap: HashMap<LocalDate, String> = HashMap()
var endDelim = "END:VEVENT"
var events: List<String> = wholeSchedule.split(endDelim)
var parsedStaffCal: ArrayList<StaffModel> = ArrayList()
var today = LocalDate.now()
// :: Pull event date from event data, pull staff list from "SUMMARY" line :: //
events.forEach {
var tempString = (it.substringAfterLast("DATE:", "FAIL").take(8))
var dateTime: LocalDate = eightIntoDateTime(tempString)
var summary: String = it.substringAfter("SUMMARY:", "FAIL")
.let { it.substringBefore("UID").replace("\\n", "\n") }
dateMap.put(dateTime, summary)
}
// ::Filter out all days before today:: //
dateMap.forEach {
if (!it.key.isBefore(today)) {
val staffModel = StaffModel(it.key, it.value)
parsedStaffCal.add(staffModel)
}
}
//:: Sort chronologically :://
parsedStaffCal.sortBy { it.localDate }
return parsedStaffCal
}
fun eightIntoDateTime(s: String): LocalDate {
return if (s.length == 8 && s.isDigitsOnly()) { // <-=-=-=-=-=- avoid potential formatting exceptions
val dateString = ("${s.subSequence(0, 4)}-${s.subSequence(4, 6)}-${s.subSequence(6, 8)}")
LocalDate.parse(dateString)
} else LocalDate.parse("1999-12-31")
}
改装API:
package com.offbroadwaystl.archdemo.schedule;
import io.reactivex.Single;
import okhttp3.ResponseBody;
import retrofit2.http.GET;
import retrofit2.http.Streaming;
public interface BearApi {
@Streaming
@GET("url.goes.here.ics")
Single<ResponseBody> getFile();
}
2条答案
按热度按时间wfveoks01#
subscribeOn
告诉可观察对象在哪里执行工作,那么observeOn
就是这个工作的结果将返回到的地方。在您的情况下,您需要:c3frrgcw2#
我认为RxJava Gradle依赖与RxKotlin依赖冲突。删除它解决了问题。我还从onSuccess中提取了一些工作,并添加了一个操作符,这可能是更好的实践:
Gradle看起来像: