【问题标题】:Caching is not working in Android Paging 3缓存在 Android Paging 3 中不起作用
【发布时间】:2020-06-16 06:08:11
【问题描述】:

我已经使用一周前发布的新 Paging 3 库的 codelabs 教程实现了应用程序。 问题是应用程序无法在离线模式下工作。它不会从 Room 数据库中检索数据。

教程回购链接:- https://github.com/googlecodelabs/android-paging

代码:-

  1. RepoDao.kt

    @Dao
    interface RepoDao {
    
       @Insert(onConflict = OnConflictStrategy.REPLACE)
       suspend fun insertAll(repos: List<Repo>)
    
       @Query("SELECT * FROM repos WHERE " +
        "name LIKE :queryString OR description LIKE :queryString " +
        "ORDER BY stars DESC, name ASC")
       fun reposByName(queryString: String): PagingSource<Int, Repo>
    
       @Query("DELETE FROM repos")
       suspend fun clearRepos()
    }
    
  2. GithubRepository.kt

    class GithubRepository(
        private val service: GithubService,
        private val database: RepoDatabase
    ) {
       fun getSearchResultStream(query: String): Flow<PagingData<Repo>> {
    
          val dbQuery = "%${query.replace(' ', '%')}%"
          val pagingSourceFactory = { database.reposDao().reposByName(dbQuery) }
    
          return Pager(
             config = PagingConfig(pageSize = NETWORK_PAGE_SIZE),
             remoteMediator = GithubRemoteMediator(
                    query,
                    service,
                    database
            ),
            pagingSourceFactory = pagingSourceFactory
          ).flow
       }
    
       companion object {
           private const val NETWORK_PAGE_SIZE = 50
       }
    }
    
  3. SearchRepositoriesViewModel.kt

    @ExperimentalCoroutinesApi
    class SearchRepositoriesViewModel(private val repository: GithubRepository) : ViewModel() {
        private var currentQueryValue: String? = null
    
        private var currentSearchResult: Flow<PagingData<Repo>>? = null
    
        fun searchRepo(queryString: String): Flow<PagingData<Repo>> {
            val lastResult = currentSearchResult
            if (queryString == currentQueryValue && lastResult != null) {
                return lastResult
            } 
            currentQueryValue = queryString
            val newResult: Flow<PagingData<Repo>> = repository.getSearchResultStream(queryString).cachedIn(viewModelScope)
            currentSearchResult = newResult
            return newResult
        }
    
    } 
    
  4. SearchRepositoriesActivity.kt

    @ExperimentalCoroutinesApi
    class SearchRepositoriesActivity : AppCompatActivity() {
    
        .....
        private lateinit var viewModel: SearchRepositoriesViewModel
        private val adapter = ReposAdapter()
    
        private var searchJob: Job? = null
    
        // this is where adapter get flow data from viewModel
        // initially this is called with **Android** as a query
        private fun search(query: String) {
            searchJob?.cancel()
            searchJob = lifecycleScope.launch {
                viewModel.searchRepo(query).collectLatest {
                    adapter.submitData(it)
                }
            }
        }
        .....
     }
    

输出:- 当应用程序在离线模式下打开时,它只是显示空的回收器视图。

【问题讨论】:

    标签: android kotlin android-room android-architecture-components android-paging


    【解决方案1】:

    如果你能够分享你的代码或者你是如何得出这个结论的,我可能会帮助你更好地查明问题,但是 codelab 确实从分支上的 Room 加载数据:step13-19_network_and_database

    这里有两个组件:

    PagingSource:由 Room 通过声明具有 PagingSource 返回类型的 @Query 提供,将创建从 Room 加载的 PagingSource。此函数在 Pager 中的 pagingSourceFactory lambda 中调用,每次调用都需要一个新实例。

    RemoteMediatorload() 在本地缓存数据不足的边界条件下调用,这将从网络获取并存储在 Room db 中,它会自动将更新传播到 Room 生成的 PagingSource 实现。

    您可能看到的另一个问题可能与 loadStateListener/Flow 有关,本质上,codelab 通过检查 CombinedLoadStates.refresh 来显示错误状态,但这始终取决于 RemoteMediator 的加载状态(如果可用)想要显示本地缓存的数据,即使RemoteMediator 出错,您也需要在这种情况下禁用隐藏列表。

    请注意,您可以使用CombinedLoadStates.sourceCombinedLoadStates.mediator 访问个人LoadState

    希望这足以帮助您,但是如果没有一些更具体的示例/关于您所看到的信息,很难猜测您的问题。

    编辑:虽然上述内容仍然是值得检查的好东西,但我在这里追查的库似乎存在潜在问题:https://android-review.googlesource.com/c/platform/frameworks/support/+/1341068

    Edit2:现在已修复,将与 alpha02 一起发布。

    【讨论】:

    • 感谢您的回复。我明白了 loadStateListener/Flow 的重点。我在日志中检查了loadState.source.refresh,它在应用程序以离线模式打开时返回NotLoading。因此,为了简单起见,我现在删除了 loadStateListener。我还在上面添加了代码。它只是显示空的回收站视图。不显示数据库中可用的数据。
    • 我还注意到,在Pager 中,如果我删除 RemoteMediator 并且只使用pagingSourceFactory,它会从数据库返回数据。所以我认为 Pager 有问题。
    • 谢谢,我已经成功地复制了这个,并在此处进行了 wip 修复,以防您想关注进度:android-review.googlesource.com/c/platform/frameworks/support/+/…
    • 我也有同样的问题。当您处于离线模式并搜索您已搜索的 Repo 时,该应用程序不会显示本地数据库中的数据。但是,尽管本地数据库中有数据,但它只显示重试按钮。我为此打开了一个 Github 问题主题:github.com/googlecodelabs/android-paging/issues/169
    猜你喜欢
    • 1970-01-01
    • 2023-01-18
    • 1970-01-01
    • 2012-06-29
    • 2020-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多