java.lang.ClassCastException: kotlinx.coroutines.CompletableDeferredImpl 无法强制转换为 java.util.List?

3
我正在开发一个新的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 articles: List, val status: String, 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 的输出是什么? - birneee
4个回答

1

不正确:

val result = sportsNewsApi.getNewsAsync()

正确:

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

异常仍然是相同的。 - Edgar
1
我非常怀疑。也许你仍然将其转换为错误的类型,但你试图转换的对象已经改变了。你应该分享你的新堆栈跟踪。 - Marko Topolnik
java.lang.ClassCastException: yodgorbek.komilov.musobaqayangiliklari.internet.SportNewsResponse无法转换为java.util.List 在yodgorbek.komilov.musobaqayangiliklari.viewmodel.MainViewModel $ loadNews $ 1.invokeSuspend(MainViewModel.kt:43) 在kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) - Edgar
我遇到了上述异常,但我不明白我做错了什么。 - Edgar
你看,现在你得到了一个“SportNewsResponse”,但却假装它是一个“List”。现在调用一个获取文章列表的方法。也许result.getArticles() - Marko Topolnik
请问在哪里实现,您能给出代码示例来解释吗? - Edgar

0

所以你已经做了一些更改。 现在,getNewsAsync必须返回UseCaseResult而不是它的列表,因为这是端点返回的内容。 然后,您可以在此对象中获取文章。


@juliribeiro 如果我进行更改,TopHeadlinesFragment.kt 会出现错误,这个逻辑我不理解。 - Edgar

0

NewsRepository中的这两行

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

你正在尝试将 result 强制转换为 UseCaseResult<List<Article>>,但在 SportNewsInterface 中,getNewsAsync() 函数返回的是 Deferred<SportNewsResponse>,因此你必须像这样将其强制转换为 UseCaseResult<Deferred<SportNewsResponse>>

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

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

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

现在别忘了将结果转换为UseCaseResult<SportNewsResponse>,并删除Deferred


C:\Users\Edgar\Desktop\SportNews\app\src\main\java\yodgorbek\komilov\musobaqayangiliklari\repository\NewsRepository.kt: (22, 60): 未解决的引用: SportNewsResponse。我遇到了以下错误,你有什么建议? - Edgar
我也尝试了你的第一种方法,但是它报错了:未解决的引用:Deferred。 - Edgar
你的项目中是否已添加了依赖项?implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2" - Mojtaba Haddadi

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

那个强制转换非常可疑,因为即使没有它也应该正常工作。这意味着你的强制转换是无效的,导致了你看到的错误。


我不明白你确切的意思。 - Edgar
getNewsAsync()并不返回一个List<Article>,所以那段代码是错误的。如果没有指定getNewsAsync()实际返回什么,就无法给出正确的实现。 - Kiskae
你认为主要问题是什么? - Edgar
尝试通过查看函数返回的类型来解释UseCaseResult<List<Article>>是什么结果,然后往回推导,因为我可以保证它没有意义。 - Kiskae
我理解你的意思,但我已经将数据类型更改为UseCaseResult<List<SportNewsResponse>>,它仍然是相同的。你有什么建议? - Edgar
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接