Android RxJava调用在I';已设置订阅(Schedulers.io())

Android RxJava调用在I';已设置订阅(Schedulers.io()),android,rx-java2,Android,Rx Java2,根据我对RxJava的理解,sendMessage()必须在后台io线程上执行,其结果可以在Android主线程上看到。然而,sendMessage()方法似乎无论如何都是在Android主线程上运行的,我的应用程序崩溃了(我在catch(e:Exception)中捕捉到它),原因是Android.os.NetworkOnMainThreadException 这是我的代码: import androidx.lifecycle.ViewModel import com.company.oplog

根据我对RxJava的理解,
sendMessage()
必须在后台io线程上执行,其结果可以在Android主线程上看到。然而,
sendMessage()
方法似乎无论如何都是在Android主线程上运行的,我的应用程序崩溃了(我在
catch(e:Exception)
中捕捉到它),原因是
Android.os.NetworkOnMainThreadException

这是我的代码:

import androidx.lifecycle.ViewModel
import com.company.oplogger.Logger
import com.company.optikbtv.utility.applySingleAsync
import com.company.optikbtv.utility.defaultErrorFun
import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider
import com.uber.autodispose.lifecycle.autoDisposable
import io.reactivex.Single
import org.koin.core.parameter.parametersOf
import org.koin.standalone.KoinComponent
import org.koin.standalone.inject
import java.io.IOException
import java.net.*

const val UDP_HOST = "10.0.2.2" // Localhost
const val UDP_PORT = 3042

class EASViewModel : ViewModel(), KoinComponent {

    private val logger: Logger by inject { parametersOf(this) }
    private lateinit var scopeProvider: AndroidLifecycleScopeProvider
    private val socket = DatagramSocket()

    fun startEAS() {
        sendMessage(socket, UDP_HOST, UDP_PORT)
            .compose(applySingleAsync())
            .doOnDispose { logger.d("Disposing subscription from the EASViewModel.startEAS()") }
            .autoDisposable(scopeProvider)
            .subscribe({
                logger.d("on Subscribe: $it")
            }, defaultErrorFun)
    }

    private fun sendMessage(socket: DatagramSocket, host: String, port: Int) : Single<Boolean> {
        val throwable: Throwable
        val message = "Hello"
        val hostAddress = InetAddress.getByName(host)

        val buf = message.toByteArray()
        try {
            logger.d("Current thread: ${Thread.currentThread().name}")
            val packet = DatagramPacket(buf, buf.size, hostAddress, port)
            socket.send(packet)
            logger.d("Sent message: $message")

            return Single.just(true)
        } catch (e: SocketException) {
            throwable = e
            e.printStackTrace()
        } catch (e: UnknownHostException) {
            throwable = e
            e.printStackTrace()
        } catch (e: IOException) {
            throwable = e
            e.printStackTrace()
        } catch (e: Exception) {
            throwable = e          // <=== This is where I get Exception
            e.printStackTrace()
        }

        return Single.error(throwable)
    }
}
我不知道到底是什么问题。

您的
sendMessage()
是一个在同步调用时同步执行的函数

只有您创建的
Single
将在IO线程上执行,但您只有常量值
Single.just()
(和
Single.error()
)可返回,因此在IO调度程序上确实没有可执行的代码

实际上,您必须提供一个代码块来构建您的
。例如,将代码包装在
Single.fromCallable{}
中,而不是使用
Single.just()

您的
sendMessage()
是一个在同步调用时同步执行的函数

只有您创建的
Single
将在IO线程上执行,但您只有常量值
Single.just()
(和
Single.error()
)可返回,因此在IO调度程序上确实没有可执行的代码


实际上,您必须提供一个代码块来构建您的
。例如,将代码包装在
Single.fromCallable{}
中,而不是使用
Single.just()

谢谢你的回答@laalto
Single.just(true)
在发生位置错误的
socket.send(packet)
之后被调用。因此,
Single.just(true)
不会被调用。另一件事是,根据我的underestanding,当我设置
.subscribeOn(Schedulers.io())
时,必须在io线程中调用
sendMessage()。这就是让我困惑的地方。是的,在到达
Single.just()
之前有一个异常
subscribeOn()
etc.影响您返回的可观察对象,而不是创建它的代码。太棒了,谢谢您的解释。我做了一个快速搜索,找到了作为参考。因此,这是我为那些有类似错误的人所做的修复:
Single.fromCallable{sendMessage(socket,UDP_主机,UDP_端口)}
谢谢你的回答@laalto
Single.just(true)
在发生位置错误的
socket.send(packet)
之后被调用。因此,
Single.just(true)
不会被调用。另一件事是,根据我的underestanding,当我设置
.subscribeOn(Schedulers.io())
时,必须在io线程中调用
sendMessage()。这就是让我困惑的地方。是的,在到达
Single.just()
之前有一个异常
subscribeOn()
etc.影响您返回的可观察对象,而不是创建它的代码。太棒了,谢谢您的解释。我做了一个快速搜索,找到了作为参考。因此,这是我为那些有类似错误设置的人所做的修复:
Single.fromCallable{sendMessage(socket,UDP_主机,UDP_端口)}
fun <T> applySingleAsync(): SingleTransformer<T, T> {
    return SingleTransformer { observable ->
        observable
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
    }
}