使用 rxandroid 和 mvvm 设计模式时出现 NetworkOnMainThreadException

NetworkOnMainThreadException when using rxandroid and mvvm design pattern

我的代码有问题,会抛出 NetworkOnMainThreadException。我正在尝试使用 Android XML-RPC 库将 Android 应用程序连接到 Odoo。

这是我正在做的事情。

class OdooServiceImpl : OdooService {
/* This is the only function doing network operation*/
override fun userAuthenticate(
    host: String,
    login: String,
    password: String,
    database: String
): Single<Int> {
    val client = XMLRPCClient("$host/xmlrpc/2/common")
    val result =
        client.call("login", database, login, password)
    return Single.just(result as Int)
}}

此 class 是从存储库 class 调用的。

存储库如果由 viewmodel class 使用 rxandroid

调用
    class OdooViewModel(private val mainRepository: OdooRepository, private val context: Context) :
    ViewModel() {
    val host = "https://myodoo-domain.com"
    private val user = MutableLiveData<OdooResource<Int>>()

    private val compositeDisposable = CompositeDisposable()

    init {
        authUser()
    }

    
    private fun authUser(){
        user.postValue(OdooResource.authConnecting(null))
        compositeDisposable.add(

            mainRepository.userAuthenticate(host,"mylogin","mypassword","mdb")
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({
                    if (it != null) {
                        user.postValue(OdooResource.authSuccess(it))
                    } else {
                        user.postValue(
                            OdooResource.authError(
                                null,
                                msg = "Something went wring while authenticating to $host"
                            )
                        )
                    }
                }, {
                    server.postValue(
                        OdooResource.conError(
                            null,
                            msg = "Something went wring while authenticating to $host"
                        )
                    )
                })
        )
    }
   
    override fun onCleared() {
        super.onCleared()
        compositeDisposable.dispose()
    }

   
    fun getUser(): LiveData<OdooResource<Int>> {
        return user
    }
}

我从我的 activity 中调用这个 class 如下

    class OdooActivity : AppCompatActivity() {
    private lateinit var odooViewModel: OdooViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_odoo)

     

        setupViewModel()

        setupObserver()
    }

    private fun setupObserver() {
        odooViewModel.getUser().observe(this, Observer {
            Log.i("TAGGG", "Tests")
            when (it.status) {
                OdooStatus.AUTHENTICATION_SUCCESS -> {
                    progressBar.visibility = View.GONE
                    it.data?.let { server -> textView.setText(server.toString()) }
                    textView.visibility = View.VISIBLE
                }

                OdooStatus.AUTHENTICATION -> {
                    progressBar.visibility = View.VISIBLE
                    textView.visibility = View.GONE
                }
                OdooStatus.AUTHENTICATION_ERROR -> {
                    //Handle Error
                    progressBar.visibility = View.GONE
                    Toast.makeText(this, it.message, Toast.LENGTH_LONG).show()
                }
                else -> {
                }
            }
        })
     
    }

    private fun setupViewModel() {
        val viewModelFactory = OdooViewModelFactory(OdooApiHelper(OdooServiceImpl()), this)
        odooViewModel = ViewModelProviders.of(this, viewModelFactory).get(OdooViewModel::class.java)
    }
}

当我 运行 应用程序这是抛出错误的行

odooViewModel = ViewModelProviders.of(this, viewModelFactory).get(OdooViewModel::class.java) 

我在这里错过了什么?

罪魁祸首在这里:

val result = client.call("login", database, login, password)
return Single.just(result as Int)

生成结果的调用在设置 Rx 链时执行,这发生在主线程上。您必须确保在实际订阅时(在 io() 上)完成网络调用。一种解决方案可能是 return a Single.fromCallable:

return Single.fromCallable { client.call("login", database, login, password) as Int }