Android 如何在kotlin协程中正确使用suspend over deferred?

Android 如何在kotlin协程中正确使用suspend over deferred?,android,kotlin,mvvm,kotlin-coroutines,retrofit2.6,Android,Kotlin,Mvvm,Kotlin Coroutines,Retrofit2.6,我正在开发新闻应用程序,自从2.6.0版本发布以来,我已经实现了kotlin协同程序,支持暂停功能。我已经在延迟函数上实现了挂起函数,但我得到的是空数据,我想知道我在哪里出错?在这里,我必须进行更正以正确显示数据获取以下异常kotlinx.coroutines.JobCancellationException:作业已取消作业=作业执行{取消}@677a578 我已在SportInterface.kt中定义了以下终点 @GET("v2/top-headlines?country=us&ap

我正在开发新闻应用程序,自从2.6.0版本发布以来,我已经实现了kotlin协同程序,支持暂停功能。我已经在延迟函数上实现了挂起函数,但我得到的是空数据,我想知道我在哪里出错?在这里,我必须进行更正以正确显示数据获取以下异常kotlinx.coroutines.JobCancellationException:作业已取消作业=作业执行{取消}@677a578

我已在SportInterface.kt中定义了以下终点

@GET("v2/top-headlines?country=us&apiKey=da331087e3f3462bb534b3b0917cbee9")
     suspend fun getNewsAsync(): SportNewsResponse
以前是在下面

 @GET("v2/top-headlines?country=us&apiKey=da331087e3f3462bb534b3b0917cbee9")
     fun getNewsAsync(): Deferred<SportNewsResponse>
下面是来自服务器的jsonResponse

{
    "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]"


        }
    ]
}
{
“状态”:“确定”,
“总体结果”:38,
“条款”:[
{
“来源”:{
“id”:“cnbc”,
“名称”:“CNBC”
},
“作者”:“Holly Ellyatt”,
“标题”:“俄罗斯现在不是北约必须处理的唯一紧迫问题——CNBC”,
“描述”:“国家元首和政府首脑将于本周在英国召开北约联盟第七十周年会议。”
“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",
“发布日期”:“2019-12-02T07:39:00Z”,
“内容”:“美国总统唐纳德·特朗普在2018年7月12日在比利时布鲁塞尔举行的2018次北约峰会上的新闻发布会上被看到。”国家元首和政府首脑们本周在英国召开了北约军事联盟第七十周年会议,讨论的是…[ + 8623个字符]。
},
{
“来源”:{
“id”:空,
“名称”:“Chron.com”
},
“作者”:“艾伦·威尔逊”,
“标题”:“德克萨斯人战胜爱国者后,比尔·奥布莱恩从德肖恩·沃森那里得到了一个游戏球——时间”,
“描述”:“在一个激动人心的时刻,德克萨斯州教练比尔·奥布莱恩在战胜新英格兰爱国者队后,被四分卫德肖恩·沃森送给了比赛用球。”,
“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",
“发布日期”:“2019-12-02T06:16:00Z”,
“内容”:“2019年12月1日,星期日,休斯顿NRG体育场,NFL与新英格兰爱国者队比赛的第四节,休斯顿得克萨斯州主教练比尔·奥布莱恩在休士顿场边。\r\n休斯顿得克萨斯州主教练比尔·奥布莱恩在四场比赛的场边……[+1583场比赛]”
}
]
}
下面是我的改装实施appmodules.kt

const val BASE_URL = "https://newsapi.org/"

val appModules = module {
    // The Retrofit service using our custom HTTP client instance as a singleton
    single {
        createWebService<SportNewsInterface>(
            okHttpClient = createHttpClient(),
            factory = RxJava2CallAdapterFactory.create(),
            baseUrl = BASE_URL
        )
    }
    // Tells Koin how to create an instance of CatRepository
    factory<NewsRepository> { (NewsRepositoryImpl(sportsNewsApi = get())) }
    // Specific viewModel pattern to tell Koin how to build MainViewModel
    viewModel { MainViewModel (newsRepository = get ())  }
}

/* Returns a custom OkHttpClient instance with interceptor. Used for building Retrofit service */
fun createHttpClient(): OkHttpClient {
    val client = OkHttpClient.Builder()
    client.readTimeout(5 * 60, TimeUnit.SECONDS)
    return client.addInterceptor {
        val original = it.request()
        val requestBuilder = original.newBuilder()
        requestBuilder.header("Content-Type", "application/json")
        val request = requestBuilder.method(original.method, original.body).build()
        return@addInterceptor it.proceed(request)
    }.build()
}

/* function to build our Retrofit service */
inline fun <reified T> createWebService(
    okHttpClient: OkHttpClient,
    factory: CallAdapter.Factory, baseUrl: String
): T {
    val retrofit = Retrofit.Builder()
        .baseUrl(baseUrl)
        .addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create()))
        .addCallAdapterFactory(CoroutineCallAdapterFactory())
        .addCallAdapterFactory(factory)
        .client(okHttpClient)
        .build()
    return retrofit.create(T::class.java)

}
const val BASE\u URL=”https://newsapi.org/"
val appModules=模块{
//将自定义HTTP客户端实例作为单例使用的改装服务
单身{
createWebService(
okHttpClient=createHttpClient(),
factory=RxJava2CallAdapterFactory.create(),
baseUrl=基本URL
)
}
//告诉Koin如何创建CatRepository的实例
工厂{(NewsRepositoryImpl(sportsNewsApi=get())}
//告诉Koin如何构建MainViewModel的特定viewModel模式
viewModel{MainViewModel(newsRepository=get())}
}
/*返回带有拦截器的自定义OkHttpClient实例。用于建筑物翻新服务*/
fun createHttpClient():OkHttpClient{
val client=OkHttpClient.Builder()
客户端读取超时(5*60,时间单位秒)
返回client.addInterceptor{
val original=it.request()
val requestBuilder=original.newBuilder()
header(“内容类型”、“应用程序/json”)
val request=requestBuilder.method(original.method,original.body.build())
return@addInterceptor继续(请求)
}.build()
}
/*功能,以建立我们的改装服务*/
内嵌式Web服务(
okHttpClient:okHttpClient,
工厂:CallAdapter.factory,baseUrl:String
):T{
val reformation=reformation.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create())
.addCallAdapterFactory(coroutineCalAdapterFactory())
.addCallAdapterFactory(工厂)
.客户(okHttpClient)
.build()
return reformation.create(T::class.java)
}
顶部标题下的片段.kt

class TopHeadlinesFragment : Fragment() {

    private val viewModel by viewModel<MainViewModel>()
    private lateinit var topHeadlinesAdapter: TopHeadlinesAdapter
   // private   val newsRepository: NewsRepository by inject()



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


        val recyclerView = view.findViewById(R.id.recyclerView) as RecyclerView
        val pb = view.findViewById(R.id.pb) as ProgressBar
        topHeadlinesAdapter = TopHeadlinesAdapter(recyclerView.context)
        recyclerView.layoutManager = LinearLayoutManager(context)
        recyclerView.adapter = topHeadlinesAdapter
        initViewModel()

        return view
    }

    private fun initViewModel() {
        viewModel?.sportList?.observe(this, Observer { newList ->
            topHeadlinesAdapter.updateData(newList)
        })

        viewModel?.showLoading?.observe(this, Observer { showLoading ->
            pb.visibility = if (showLoading) View.VISIBLE else View.GONE
        })

        viewModel?.showError?.observe(this, Observer { showError ->
            (showError)
        })

        viewModel?.loadNews()
    }
}
class-TopHeadlinesFragment:Fragment(){
私有val viewModel by viewModel()
私有lateinit变量topHeadlinesAdapter:topHeadlinesAdapter
//private val newsRepository:newsRepository by inject()
//3
覆盖创建视图(
充气机,
容器:视图组?,
savedInstanceState:捆绑?
):查看{
val视图=充气机。充气(
R.layout.fragment_顶部标题
,货柜,虚假
)
val recyclerView=view.findviewbyd(R.id.recyclerView)作为recyclerView
val pb=view.findviewbyd(R.id.pb)作为进度条
topHeadlinesAdapter=topHeadlinesAdapter(recyclerView.context)
recyclerView.layoutManager=LinearLayoutManager(上下文)
recyclerView.adapter=topHeadlinesAdapter
initViewModel()
返回视图
}
私有视图模型(){
viewModel?.sportList?.observe(此,观察者{newList->
topHeadlinesAdapter.updateData(新列表)
})
viewModel?.showLoading?.observe(此,观察者{showLoading->
pb.visibility=if(showLoading)View.visibility else View.go
})
viewModel?.sparhorror?.observe(这个,观测者{sparhorror->
(淋浴器)
})
viewModel?.loadNews()
}
}

A旁白:没有理由拒绝你
@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
)
{
    "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]"


        }
    ]
}
const val BASE_URL = "https://newsapi.org/"

val appModules = module {
    // The Retrofit service using our custom HTTP client instance as a singleton
    single {
        createWebService<SportNewsInterface>(
            okHttpClient = createHttpClient(),
            factory = RxJava2CallAdapterFactory.create(),
            baseUrl = BASE_URL
        )
    }
    // Tells Koin how to create an instance of CatRepository
    factory<NewsRepository> { (NewsRepositoryImpl(sportsNewsApi = get())) }
    // Specific viewModel pattern to tell Koin how to build MainViewModel
    viewModel { MainViewModel (newsRepository = get ())  }
}

/* Returns a custom OkHttpClient instance with interceptor. Used for building Retrofit service */
fun createHttpClient(): OkHttpClient {
    val client = OkHttpClient.Builder()
    client.readTimeout(5 * 60, TimeUnit.SECONDS)
    return client.addInterceptor {
        val original = it.request()
        val requestBuilder = original.newBuilder()
        requestBuilder.header("Content-Type", "application/json")
        val request = requestBuilder.method(original.method, original.body).build()
        return@addInterceptor it.proceed(request)
    }.build()
}

/* function to build our Retrofit service */
inline fun <reified T> createWebService(
    okHttpClient: OkHttpClient,
    factory: CallAdapter.Factory, baseUrl: String
): T {
    val retrofit = Retrofit.Builder()
        .baseUrl(baseUrl)
        .addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create()))
        .addCallAdapterFactory(CoroutineCallAdapterFactory())
        .addCallAdapterFactory(factory)
        .client(okHttpClient)
        .build()
    return retrofit.create(T::class.java)

}
class TopHeadlinesFragment : Fragment() {

    private val viewModel by viewModel<MainViewModel>()
    private lateinit var topHeadlinesAdapter: TopHeadlinesAdapter
   // private   val newsRepository: NewsRepository by inject()



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


        val recyclerView = view.findViewById(R.id.recyclerView) as RecyclerView
        val pb = view.findViewById(R.id.pb) as ProgressBar
        topHeadlinesAdapter = TopHeadlinesAdapter(recyclerView.context)
        recyclerView.layoutManager = LinearLayoutManager(context)
        recyclerView.adapter = topHeadlinesAdapter
        initViewModel()

        return view
    }

    private fun initViewModel() {
        viewModel?.sportList?.observe(this, Observer { newList ->
            topHeadlinesAdapter.updateData(newList)
        })

        viewModel?.showLoading?.observe(this, Observer { showLoading ->
            pb.visibility = if (showLoading) View.VISIBLE else View.GONE
        })

        viewModel?.showError?.observe(this, Observer { showError ->
            (showError)
        })

        viewModel?.loadNews()
    }
}