【问题标题】:Cannot display coroutine error message to users from ViewModel无法从 ViewModel 向用户显示协程错误消息
【发布时间】:2020-08-30 08:17:56
【问题描述】:

当 Retrofit API 调用出现问题时,我正在尝试向用户显示错误消息。我正在使用 Kotlin Coroutines、Kodein 和 MVVM 模式。鉴于在片段中没有真正观察到 MutableLiveData 异常消息,我无法在 toast 消息中显示错误消息(我猜这与通过 API 获取数据的异步函数的性质有关(暂停乐趣))。

视图模型:

class BarcodeViewModel(
    private val barcodeRepository: BarcodeRepository,
    private val productRepository: ProductRepository
) : ViewModel() {

    var exceptionMessage: MutableLiveData<String> = MutableLiveData()

    private val handler = CoroutineExceptionHandler { _, exception ->
        exceptionMessage.value = exception.localizedMessage
    }

    fun getBarcodeData(barcode: String) {
        CoroutineScope(Dispatchers.Main).launch(handler) {
            val currentArticle = barcodeRepository.getProductData(barcode)

            for (article in currentArticle.products) {
                val articleToAdd =
                    Product(...)

                val articleDb = productRepository.getProduct(barcode)
                if (articleDb.isEmpty()) {
                    productRepository.addProduct(articleToAdd)
                    exceptionMessage.value = ""
                } else {
                    exceptionMessage.value = "Product already exists"
                }
            }
        }
    }
}

片段:

class ArticleAddFragment : Fragment(), LifecycleOwner, KodeinAware {
    override val kodein: Kodein by kodein()
    private val factory: BarcodeViewModelFactory by instance()
    private lateinit var viewModel: BarcodeViewModel

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    val view = inflater.inflate(R.layout.fragment_article_add, container, false)

    viewModel = ViewModelProviders.of(this, factory).get(BarcodeViewModel::class.java)

    ...

    return view
}

private fun processResult(firebaseVisionBarcodes: List<FirebaseVisionBarcode>) {
    if (firebaseVisionBarcodes.isNotEmpty()) {
        for (item in firebaseVisionBarcodes) {
            when (item.valueType) {
                FirebaseVisionBarcode.TYPE_PRODUCT -> {
                    viewModel.getBarcodeData(item.rawValue!!)
                    viewModel.exceptionMessage.observe(viewLifecycleOwner, Observer {
                        it?.let {
                            if (!it.isBlank()) {
                                Toast.makeText(context, it, Toast.LENGTH_SHORT).show()
                            }
                        }
                    })
                    ...
                }
            }
        }
    }
}

在 toast 中显示错误消息的最聪明的方法是什么?

【问题讨论】:

  • 什么时候调用processResult?我认为您应该在 onViewCreated 中观察 LiveData,这意味着片段已经创建了 viewLifecycleOwner。
  • 在 onCreate 方法中调用另一个方法来启动相机,如果相机在来自相机的实时馈送中找到条形码则调用 processResult。我已经尝试在 onViewCreated 中观察 LiveData,但即使在协程中抛出异常,它也始终为空:/
  • CoroutineScope(Dispatchers.Main).launch(handler) 这项工作是否正在完成或导致任何异常以及是否要显示异常 message.value = "产品已存在"?

标签: android kotlin retrofit kotlin-coroutines


【解决方案1】:

我建议使用密封类或枚举来更新和观察状态。

State.kt

sealed class State<T> {
    class Loading<T> : State<T>()

    data class Success<T>(val data: T) : State<T>()

    data class Error<T>(val message: String) : State<T>()

    companion object {

        /**
         * Returns [State.Loading] instance.
         */
        fun <T> loading() = Loading<T>()

        /**
         * Returns [State.Success] instance.
         * @param data Data to emit with status.
         */
        fun <T> success(data: T) = Success(data)

        /**
         * Returns [State.Error] instance.
         * @param message Description of failure.
         */
        fun <T> error(message: String) = Error<T>(message)
    }

}

类是通用的,因此您可以根据成功和失败相应地放置数据。

【讨论】:

    猜你喜欢
    • 2011-11-03
    • 2020-03-18
    • 2019-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多