在 ViewModel 中使用 viewModelScope.launch 调用暂停方法时出现 "No virtual method getTag(Ljava/lang/String;)" 错误

Getting "No virtual method getTag(Ljava/lang/String;)" error when calling suspended method using viewModelScope.launch inside ViewModel

我正在尝试通过 viewModelScope.launch() 调用挂起的方法,但应用程序在调用该方法后立即崩溃。

我应该指出,我使用的是最新版本的 androidX 稳定库。 然而,对于 ViewModel 和 LiveData,我使用的是 2.2.0-alpha02 的 alpha 版本。 当然,Retrofit 版本是 2.6.0,所以将它的功能标记为暂停应该没问题。

此外,变量是使用 Koin 初始化的。

日志:

java.lang.NoSuchMethodError: No virtual method getTag(Ljava/lang/String;)Ljava/lang/Object; in class Landroidx/lifecycle/ViewModel; or its super classes (declaration of 'androidx.lifecycle.ViewModel' appears in /data/app/co.nilin.varabank-lUNWj0JGUm_fCoYkMmbbJg==/base.apk)
        at androidx.lifecycle.ViewModelKt.getViewModelScope(ViewModel.kt:36)
        at co.nilin.varabank.home.HomeViewModel.fetchRates(HomeViewModel.kt:18)
        at co.nilin.varabank.home.HomeActivity$init.onClick(HomeActivity.kt:27)
        at android.view.View.performClick(View.java:6597)
        at android.view.View.performClickInternal(View.java:6574)
        at android.view.View.access00(View.java:778)
        at android.view.View$PerformClick.run(View.java:25885)
        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)

改造网络服务:

interface BankCalculatorWebService {
    @GET("auto/bank-gateway/general/{bank}/currencies")
    suspend fun fetchCurrencyRates(@Path("bank") bank: String): Response<CurrencyRateResponse>
}

存储库:

class BankCalculatorRepositoryImpl(
    private val webService: BankCalculatorWebService
) : BankCalculatorRepository {
    override suspend fun fetchRates(): List<CurrencyRateDTO> {
        val list = ArrayList<CurrencyRateDTO>()
        val response = webService.fetchCurrencyRates(Bank.getDefaultBank().swiftCode)
        response.ifSuccessful { response ->
            response.items.forEach {
                list.add(CurrencyRateDTO.fromCurrencyRate(it))
            }
        }
        return list
    }
}

查看模型:

class HomeViewModel(
    private val repository: BankCalculatorRepository
) : ViewModel() {
    val rates = MutableLiveData<List<CurrencyRateDTO>>()

    fun fetchRates() {
        viewModelScope.launch {
            val response = repository.fetchRates()
            rates.postValue(response)
        }
    }
}

里面的代码activity

viewModel.rates.observe(this) {
    Toast.makeText(this, it.size, Toast.LENGTH_SHORT).show()
}

button.setOnClickListener {
    viewModel.fetchRates()
}

我也遇到了同样的问题。除了自己实现 viewModelScope 之外,我找不到任何解决方案。您的 HomeViewModel 代码将如下所示

 class HomeViewModel(
    private val repository: BankCalculatorRepository
) : ViewModel() {

private val viewModelJob = SupervisorJob()
protected val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)

val rates = MutableLiveData<List<CurrencyRateDTO>>()

    fun fetchRates() {
        uiScope.launch {
            val response = repository.fetchRates()
            rates.postValue(response)
        }
    }

    /**
     * Cancel all coroutines when the ViewModel is cleared
     */
    override fun onCleared() {
        super.onCleared()
        uiScope.coroutineContext.cancelChildren()
    }
}

这是由于对 androidx.lifecycle.ViewModel class 不同版本的依赖污染了您的 class 路径(可能是 2.2.0 和 2.0.0 版本)。这通常是由于来自过时库的传递依赖。对我来说,是 support-v4 库导致的。

运行 ./gradlew app:dependencies 查看您的树,然后查找 ViewModel 上的传递依赖项。对于那些正在引入旧版本的库,要么更新它们,要么为它们排除 ViewModel 依赖项:

implemenation ("com.<library>") {
    exclude group:'androidx.lifecycle', module:'lifecycle-viewmodel'
}