Я занимаюсь разработкой новостей и реализовал сопрограммы Kotlin с помощью Koin. Я успешно создал класс модулей, но не могу передать правильный параметр в класс ViewModel, чтобы при успешном получении данных с сервера на нем отображались данные, поступающие с сервера. когда нет данных, выводится сообщение об ошибке
ниже класса моего модуля
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( sportNewsInterface= get())) }
// Specific viewModel pattern to tell Koin how to build MainViewModel
viewModel { MainViewModel(sportNewsInterface = 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)
}
ниже MainViewModel.kt, где я вызываю сопрограммы Kotlin
class MainViewModel(
private val sportNewsInterface: SportNewsInterface
) : ViewModel(), CoroutineScope {
// Coroutine's background job
private val job = Job()
// Define default thread for Coroutine as Main and add job
override val coroutineContext: CoroutineContext = Dispatchers.Main + job
private val showLoading = MutableLiveData<Boolean>()
private val sportList = MutableLiveData <List<SportNewsResponse>>()
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) { sportNewsInterface.getNews() }
// Hide progressBar once the operation is done on the MAIN (default) thread
showLoading.value = false
when (result) {
is UseCaseResult.Success<List<SportNewsResponse> -> sportList.value = result.data
is UseCaseResult.Error -> showError.value = result.exception.message
}
}
}
override fun onCleared() {
super.onCleared()
// Clear our job when the linked activity is destroyed to avoid memory leaks
job.cancel()
}
}
ниже UseCaseResult. kt
sealed class UseCaseResult<out T : Any> {
class Success<out T : Any>(val data: T) : UseCaseResult<<List<SportNewsResponse>>>()
class Error(val exception: Throwable) : UseCaseResult<Nothing>()
}
ниже SportInterface
interface SportNewsInterface {
@GET("v2/top-headlines?country=us&apiKey=da331087e3f3462bb534b3b0917cbee9")
suspend fun getNews(): List<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>>
}
ниже Класс модели
data class SportNewsResponse(
val articles: List<Article>,
val status: String,
val totalResults: Int
)