#android #kotlin-coroutines
#Android #kotlin-сопрограммы
Вопрос:
Я хочу получить данные из источника данных. Но, оказывается, он вообще не выполнялся. Как я могу это решить? вот мой код
Repository.kt
// all logcat in repository is executed
override fun getDetailGame(id: Int): Flow<Resource<Game>> {
Log.d("Repo", "getDetailGame: called")
return flow {
Log.d("Repo", "getDetailGame: before flow")
remoteDataSource.getDetailGame(id)
Log.d("Repo", "getDetailGame: after flow")
}
}
Datasource.kt
suspend fun getDetailGame(id: Int): Flow<ApiResponse<GameResponse>> =
flow {
try {
// didnt get executed all
Log.d(TAG, "getDetailGame: called")
val response = apiService.getDetailGame(id)
if (response != null) {
emit(ApiResponse.Success(response))
} else {
emit(ApiResponse.Empty)
}
} catch (ex: Exception) {
emit(ApiResponse.Error(ex.message.toString()))
Log.e(TAG, "getDetailGame: ${ex.message} ")
}
}.flowOn(Dispatchers.IO)
Редактировать: добавить дополнительный код для другого файла
ApiResponse.kt (управление состоянием ответа для источника данных)
sealed class ApiResponse<out R> {
data class Success<out T>(val data: T) : ApiResponse<T>()
data class Error(val errorMessage: String) : ApiResponse<Nothing>()
object Empty : ApiResponse<Nothing>()
}
Resource.kt (управление состоянием пользовательского интерфейса, например, состояние загрузки и т. Д.)
sealed class Resource<T>(val data: T? = null, val message: String? = null) {
class Success<T>(data: T) : Resource<T>(data)
class Loading<T>(data: T? = null) : Resource<T>(data)
class Error<T>(message: String, data: T? = null) : Resource<T>(data, message)
}
GameResponse.kt (то же, что и Game, но с serializedname для json)
data class GameResponse(
@field:SerializedName("id")
var id: Int,
@field:SerializedName("name")
var title: String,
@field:SerializedName("released")
var released: String? = null,
@field:SerializedName("metacritic")
var metacritic: Int? = null,
@field:SerializedName("metacritic_url")
var metacriticUrl: Int? = null,
@field:SerializedName("background_image")
var bgImage: String? = null,
@field:SerializedName("description")
var description: String? = null,
@field:SerializedName("game_series_count")
var gameSeriesCount: Int? = 0
)
Game.kt (такой же, как GameResponse, но его чистая версия)
data class Game(
var id: Int,
var title: String,
var released: String? = null,
var metacritic: Int? = null,
var metacriticUrl: Int? = null,
var bgImage: String? = null,
var description: String? = null,
var gameSeriesCount: Int? = 0
)
Ответ №1:
Потоки — это холодные потоки, это означает, что они не будут выполняться, пока вы их не соберете. Если вы пытаетесь преобразовать Flow<ApiResponse>
в Flow<Resource>
, вам следует использовать map
функцию. Если вам нужно более сложное преобразование, используйте transform
вместо этого.
override fun getDetailGame(id: Int): Flow<Resource<GameResponse>> {
return remoteDataSource.getDetailGame(id).map { response ->
when (response) {
ApiResponse.Empty -> Resource.Loading()
is ApiResponse.Success -> Resource.Success(response.data)
is ApiResponse.Error -> Resource.Error(response.errorMessage)
}
}
}
Или, если вам нужно передать значение перед выполнением преобразования:
override fun getDetailGame(id: Int): Flow<Resource<GameResponse>> = flow {
emit(Resource.Loading())
emitAll(
remoteDataSource.getDetailGame(id).map { response ->
when (response) {
is ApiResponse.Success -> Resource.Success(response.data)
is ApiResponse.Error -> Resource.Error(response.errorMessage)
ApiResponse.Empty -> Resource.Error("")
}
}
)
}
Комментарии:
1. Любая ссылка на то, как выполнить преобразование?
2. Я не знаю, что вы пытаетесь сделать, и для того, чтобы помочь вам, мне нужно увидеть эти классы: ApiResponse, GameResponse, Resource, Game
3. ApiResponse и Resource — это закрытый класс для управления состоянием. Game и GameResponse — это один и тот же класс данных, GameResponse имеет serializedname для извлечения ключа из JSON и отобразит его в классе игровых данных. Все свойства обоих классов одинаковы.
4. можете ли вы добавить их в свой вопрос?
5. добавлено к сообщению сэр