fix(android): avoid two unnecessary API calls in search

This commit is contained in:
Harsh Shandilya 2023-11-18 14:54:22 +05:30
parent fdb79d4a6d
commit 1d3d4f7455
2 changed files with 16 additions and 10 deletions

View file

@ -14,6 +14,7 @@ import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dev.msfjarvis.claw.android.paging.LobstersPagingSource.Companion.PAGE_SIZE
import dev.msfjarvis.claw.android.paging.LobstersPagingSource.Companion.STARTING_PAGE_INDEX
import dev.msfjarvis.claw.api.LobstersSearchApi
import dev.msfjarvis.claw.core.injection.IODispatcher
import dev.msfjarvis.claw.model.LobstersPost
import java.io.IOException
@ -21,15 +22,16 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
/**
* Duplicate of [LobstersPagingSource] with an additional optimization to not continue loading
* further pages if nothing is found in the current one. This is required to prevent the app from
* hammering the search endpoint with up to 70 consecutive requests for the search results of a
* blank query.
* Specialized variant of [LobstersPagingSource] to prevent hammering the Lobsters search endpoint
* with unnecessary requests. Rather than abstract out the API call this paging source takes in the
* relevant parameters to short-circuit when there is no query specified in order to avoid calling
* the API at all.
*/
class SearchPagingSource
@AssistedInject
constructor(
@Assisted private val remoteFetcher: RemoteFetcher<LobstersPost>,
private val searchApi: LobstersSearchApi,
@Assisted private val queryProvider: () -> String,
@IODispatcher private val ioDispatcher: CoroutineDispatcher,
) : PagingSource<Int, LobstersPost>() {
override fun getRefreshKey(state: PagingState<Int, LobstersPost>): Int? {
@ -39,8 +41,14 @@ constructor(
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, LobstersPost> {
val searchQuery = queryProvider()
// If there is no query, we don't need to call the API at all.
if (searchQuery.isEmpty()) {
return LoadResult.Page(itemsBefore = 0, data = emptyList(), prevKey = null, nextKey = null)
}
val page = params.key ?: STARTING_PAGE_INDEX
return when (val result = withContext(ioDispatcher) { remoteFetcher.getItemsAtPage(page) }) {
val result = withContext(ioDispatcher) { searchApi.searchPosts(searchQuery, page) }
return when (result) {
is ApiResult.Success -> {
// Optimization: prevent fetching more pages if we found no items, this means
// there is no active search query.
@ -62,6 +70,6 @@ constructor(
@AssistedFactory
interface Factory {
fun create(remoteFetcher: RemoteFetcher<LobstersPost>): SearchPagingSource
fun create(queryProvider: () -> String): SearchPagingSource
}
}

View file

@ -27,7 +27,6 @@ import dev.msfjarvis.claw.android.paging.LobstersPagingSource.Companion.PAGE_SIZ
import dev.msfjarvis.claw.android.paging.LobstersPagingSource.Companion.STARTING_PAGE_INDEX
import dev.msfjarvis.claw.android.paging.SearchPagingSource
import dev.msfjarvis.claw.api.LobstersApi
import dev.msfjarvis.claw.api.LobstersSearchApi
import dev.msfjarvis.claw.core.injection.IODispatcher
import dev.msfjarvis.claw.core.injection.MainDispatcher
import dev.msfjarvis.claw.database.local.SavedPost
@ -57,7 +56,6 @@ class ClawViewModel
@Inject
constructor(
private val api: LobstersApi,
private val searchApi: LobstersSearchApi,
private val commentsRepository: CommentsRepository,
private val readPostsRepository: ReadPostsRepository,
private val savedPostsRepository: SavedPostsRepository,
@ -79,7 +77,7 @@ constructor(
}
private val searchResultsPager =
Pager(PagingConfig(pageSize = PAGE_SIZE), initialKey = STARTING_PAGE_INDEX) {
searchPagingSourceFactory.create { searchApi.searchPosts(searchQuery, it) }
searchPagingSourceFactory.create { searchQuery }
}
val hottestPosts