networkBoundResource - не получается кешировать данные, преобразованые с помощью Android Paging (type mismatch). Что переделать, а что оставить?
У меня response от API-запроса содержит объект Response в котором внутри List. В коде PagingSource (внизу) из ответа вынимается этот List и преобразуется в PagingData. Из репозитория я эту дату вызываю и прежде чем отправлять во вьюМодель, мне ее надо кешировать. И тут проблема, т.к. в Dao я понимаю только как добавлять List, и в репозитоии выходит type mismatch. Что именно нужно переделывать? Сами методы в Dao? Или какойто преобразователь в репозитоирии дописать? в самой функции networkBoudResource же вроде все нормально.
Буду благодарен за помощь потому что эти темы (кеширование и Paging) для меня совсем новые и я запутался.
Код репозитория:
class VkRepository @Inject constructor( private val vkApi: VkApi, private val db: VkPersonDatabase ) {
private val personDao = db.personDao()
fun getUserFriendsResults(userId: String) =
Pager(
config = PagingConfig(
pageSize = 20,
maxSize = 100,
enablePlaceholders = false
),
pagingSourceFactory = { VkPagingSource(vkApi, userId) }
).liveData
fun getPeople(userId: String) = networkBoundResource(
query = {
personDao.getAllPeople()
},
fetch = {
delay(2000)
getUserFriendsResults(userId)
},
saveFetchResult = { people ->
db.withTransaction {
personDao.deleteAllPeople()
personDao.insertPeople(people) // ВОТ ЗДесь ошибка Type mismatch.
// Required: List<VkPerson> Found: LiveData<PagingData<VkPerson>>
}
}
)
У меня в Апях такой метод:
@GET("method/friends.get")
suspend fun searchFriends(
@Query("user_id") id: String,
@Query("fields") fields: String,
@Query("v") apiVersion: String,
@Query("access_token") accessToken: String
) : VkResponse
И результат API запроса , прежде чем попасть в репозиторий и дальше во вьюмодель, пропускается через вот такой PagingSource:
class VkPagingSource(
private val vkApi: VkApi,
private val userId: String
) : PagingSource<Int, VkPerson>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, VkPerson> {
val position = params.key ?: VK_STARTING_PAGE_INDEX
return try {
val vkResponse = vkApi.searchFriends(userId, /*2,*/ "city,domain,photo_200_orig", VkApi.API_VERSION, VkApi.ACCESS_TOKEN)
val people = vkResponse.response.items
LoadResult.Page(
data = people,
prevKey = if (position == VK_STARTING_PAGE_INDEX) null else position - 1,
nextKey = if (people.isEmpty()) null else position + 1
)
} catch (exception: IOException) {
LoadResult.Error(exception)
} catch (exception: HttpException) {
LoadResult.Error(exception)
}
}
}
При этом у меня есть база, и я хочу кешировать данные приходящие в response на случай плохого интернет соединения итд. Чтобы кешировать и доставать из кеша в Dao есть методы:
@Query("SELECT * FROM people")
fun getAllPeople(): Flow<List<VkPerson>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertPeople(people: List<VkPerson>)
@Query("DELETE FROM people")
suspend fun deleteAllPeople()
Ну и соответственно, на всякий случай, выложу код NetworkBoundResource:
sealed class Resource<T>(
val data: T? = null,
val error: Throwable? = null
) {
class Success<T>(data: T) : Resource<T>(data)
class Loading<T>(data: T? = null) : Resource<T>(data)
class Error<T>(throwable: Throwable, data: T? = null) : Resource<T>(data, throwable)
}
И:
inline fun <ResultType, RequestType> networkBoundResource(
crossinline query: () -> Flow<ResultType>,
crossinline fetch: suspend () -> RequestType,
crossinline saveFetchResult: suspend (RequestType) -> Unit,
crossinline shouldFetch: (ResultType) -> Boolean = { true }
) = flow {
val data = query().first()
val flow = if (shouldFetch(data)) {
emit(Resource.Loading(data))
try {
saveFetchResult(fetch())
query().map { Resource.Success(it) }
} catch (throwable: Throwable) {
query().map { Resource.Error(throwable, it) }
}
} else {
query().map { Resource.Success(it) }
}
emitAll(flow)
}