【问题标题】:java.lang.ClassCastException: kotlinx.coroutines.CompletableDeferredImpl cannot be cast to java.util.List?java.lang.ClassCastException:kotlinx.coroutines.CompletableDeferredImpl 不能转换为 java.util.List?
【发布时间】:2020-04-03 09:17:48
【问题描述】:

我正在开发一个新的 android 应用程序,但出现以下异常

java.lang.ClassCastException: kotlinx.coroutines.CompletableDeferredImpl cannot be cast to java.util.List
    at yodgorbek.komilov.musobaqayangiliklari.viewmodel.MainViewModel$loadNews$1.invokeSuspend(MainViewModel.kt:42)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:201)
    at android.app.ActivityThread.main(ActivityThread.java:6820)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:922)

在我的 MainViewModel.kt 中

在我的 MainViewModel.kt 下方

@Suppress("UNCHECKED_CAST")
class MainViewModel(val newsRepository: NewsRepository) : ViewModel(), CoroutineScope {
    // Coroutine's background job
    val job = Job()
    // Define default thread for Coroutine as Main and add job
    override val coroutineContext: CoroutineContext = Dispatchers.Main + job

    val showLoading = MutableLiveData<Boolean>()
    val sportList = MutableLiveData <List<Article>>()
    val showError = SingleLiveEvent<String>()

    fun loadNews() {
        // Show progressBar during the operation on the MAIN (default) thread
        showLoading.value = true
        // launch the Coroutine
        launch {
            // Switching from MAIN to IO thread for API operation
            // Update our data list with the new one from API
            val result = withContext(Dispatchers.IO) {
                newsRepository?.getNewsList()
            }
            // Hide progressBar once the operation is done on the MAIN (default) thread
            showLoading.value = false
            when (result) {

                is UseCaseResult.Success<*> -> {
                    sportList.value = result.data as List<Article>
                }
                is Error -> showError.value = result.message
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        // Clear our job when the linked activity is destroyed to avoid memory leaks
        job.cancel()
    }
}

在 Article.kt 下方

@Entity(tableName = "news_table")
data class Article(@ColumnInfo(name = "author")val author: String,
                   val content: String,
                   val description: String,
                   val publishedAt: String,
                   val source: Source,
                   val title: String,
                   val url: String,
                   val urlToImage: String
)

在 SportNewsResponse.kt 下方

数据类 SportNewsResponse( val 文章:列表, 验证状态:字符串, val totalResults: Int )

在 UseCaseResult.kt 下方

sealed class UseCaseResult<out T : Any>() {
    class Success<out T : Any>(val data: T) : UseCaseResult<T>()
    class Error(val exception: Throwable) : UseCaseResult<Nothing>()
}

在我实现 UserCaseResult 的 NewsRepository.kt 下方

interface NewsRepository {
    // Suspend is used to await 
    suspend fun getNewsList(): UseCaseResult<List<Article>>
}


@Suppress("UNCHECKED_CAST")
class NewsRepositoryImpl(private val sportsNewsApi: SportNewsInterface) : NewsRepository {
    override suspend fun getNewsList(): UseCaseResult<List<Article>> {

        return try {
            val result = sportsNewsApi.getNewsAsync()
            UseCaseResult.Success(result) as UseCaseResult<List<Article>>
        } catch (ex: Exception) {
            UseCaseResult.Error(ex)
        }
    }
}

在我的 SportNewsInteface.kt 下方

interface SportNewsInterface {

    @GET("v2/top-headlines?country=us&apiKey=da331087e3f3462bb534b3b0917cbee9")
     fun getNewsAsync(): Deferred<SportNewsResponse>

    @GET("/v2/top-headlines?sources=espn&apiKey=da331087e3f3462bb534b3b0917cbee9")
    fun getEspn(): Deferred<List<SportNewsResponse>>

    @GET("/v2/top-headlines?sources=football-italia&apiKey=da331087e3f3462bb534b3b0917cbee9")
    fun getFootballItalia(): Deferred<List<SportNewsResponse>>

    @GET("/v2/top-headlines?sources=bbc-sport&apiKey=da331087e3f3462bb534b3b0917cbee9")
    fun getBBCSport(): Deferred<List<SportNewsResponse>>

在我的服务器响应下方

{
    "status": "ok",
    "totalResults": 38,
    "articles": [
        {
            "source": {
                "id": "cnbc",
                "name": "CNBC"
            },
            "author": "Holly Ellyatt",
            "title": "Russia is now not the only pressing issue that NATO has to deal with - CNBC",
            "description": "Heads of state and government are meeting in the U.K. this week for the 70th anniversary of the military alliance NATO.",
            "url": "https://www.cnbc.com/2019/12/02/nato-summit-alliance-has-more-pressing-issues-than-russia-now.html",
            "urlToImage": "https://image.cnbcfm.com/api/v1/image/106272467-1575218599700gettyimages-997112494.jpeg?v=1575218712",
            "publishedAt": "2019-12-02T07:39:00Z",
            "content": "US president Donald Trump is seen during his press conference at the 2018 NATO Summit in Brussels, Belgium on July 12, 2018.\r\nAs heads of state and government meet in the U.K. this week for the 70th anniversary of the military alliance NATO, discussions are l… [+8623 chars]"
        },
        {
            "source": {
                "id": null,
                "name": "Chron.com"
            },
            "author": "Aaron Wilson",
            "title": "Bill O'Brien gets game ball from Deshaun Watson after Texans' win over Patriots - Chron",
            "description": "In an emotional moment, Texans coach Bill O'Brien was presented with the game ball by quarterback Deshaun Watson following a pivotal win over the New England Patriots.",
            "url": "https://www.chron.com/sports/texans/article/Bill-O-Brien-Deshaun-Watson-Texans-Patriots-14874678.php",
            "urlToImage": "https://s.hdnux.com/photos/01/07/23/50/18692664/3/rawImage.jpg",
            "publishedAt": "2019-12-02T06:16:00Z",
            "content": "<ul><li>Houston Texans head coach Bill O'Brien on the sidelines during the fourth quarter of an NFL game against the New England Patriots at NRG Stadium Sunday, Dec. 1, 2019, in Houston.\r\nHouston Texans head coach Bill O'Brien on the sidelines during the four… [+1583 chars]"


        }
    ]
}

【问题讨论】:

  • result.data.await()::class 的输出是什么?

标签: android kotlin viewmodel classcastexception kotlin-coroutines


【解决方案1】:

不正确:

val result = sportsNewsApi.getNewsAsync()

正确:

val result = sportsNewsApi.getNewsAsync().await()

【讨论】:

  • 异常还是一样
  • 我非常怀疑这一点。也许您仍在转换为错误的类型,但您尝试转换的对象已更改。你应该分享你的新堆栈跟踪。
  • java.lang.ClassCastException: yodgorbek.komilov.musobaqayangiliklari.internet.SportNewsResponse 无法在 yodgorbek.komilov.musobaqayangiliklari.viewmodel.MainViewModel$loadNews$1.invokeSuspend(MainViewModel. kt:43) 在 kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
  • 我正在超越异常我不明白我做错了什么
  • 嗯,你看,现在你得到了一个SportNewsResponse,但假装它是一个List。现在调用一个获取文章列表的方法。也许result.getArticles().
【解决方案2】:
  val result = sportsNewsApi.getNewsAsync()
  UseCaseResult.Success(result) as UseCaseResult<List<Article>>

该演员表非常可疑,因为即使没有它也应该可以工作。这意味着您的演员表无效,导致您看到的错误。

【讨论】:

  • 我不明白你的意思
  • getNewsAsync() 不返回List&lt;Article&gt;,因此该代码不正确。如果不指定 getNewsAsync() 实际返回的内容,就无法给出正确的实现。
  • 它返回 SportNewsResponse 结束点,我现在将添加到代码中
  • 我已经添加了所有必要的文件,请检查它
  • 你认为主要问题是什么
【解决方案3】:

所以你已经做了一些改变 现在 getNewsAsync 必须返回 UseCaseResult 而不是它的列表,因为这就是端点返回的内容。 然后就可以拿到这个对象里面的文章了

【讨论】:

  • @juliribeiro 如果我更改,我在 TopHeadlinesFragment.kt 中遇到错误,这是我不理解的逻辑
【解决方案4】:

NewsRepository 在这 2 行中

 val result = sportsNewsApi.getNewsAsync()
 UseCaseResult.Success(result) as UseCaseResult<List<Article>>

您正在尝试将result 转换为UseCaseResult&lt;List&lt;Article&gt;&gt; ,但在 SportNewsInterface 中,getNewsAsync() fun 返回 Deferred&lt;SportNewsResponse&gt;,因此您必须像这样将其转换为 UseCaseResult&lt;Deferred&lt;SportNewsResponse&gt;&gt;

UseCaseResult.Success(result) as UseCaseResult<Deferred<SportNewsResponse>>

或者如果您想获取值,请像这样在getNewsAsync() 上使用.await()

val result = sportsNewsApi.getNewsAsync().await()
 UseCaseResult.Success(result) as UseCaseResult<SportNewsResponse>

不要忘记现在您应该将结果转换为 UseCaseResult&lt;SportNewsResponse&gt; 并删除 Deferred

【讨论】:

  • C:\Users\Edgar\Desktop\SportNews\app\src\main\java\yodgorbek\komilov\musobaqayangiliklari\repository\NewsRepository.kt: (22, 60): Unresolved reference: SportNewsResponse I在您的建议下方出现错误
  • 我也尝试过你的第一种方法,它给出了这个错误未解决的参考:延迟
  • 您是否为项目添加了依赖项? implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2"
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-22
相关资源
最近更新 更多