【问题标题】:Android Jetpack Paging3 calling PagingSource with different dataAndroid Jetpack Paging3 使用不同的数据调用 PagingSource
【发布时间】:2022-10-04 19:35:26
【问题描述】:

我正在制作一个电影应用程序,在单击类型按钮时,它应该使用不同发送的数据进行 api 调用。 即,每当用户单击系列或电影按钮时,它应该使用该特定参数进行 API 调用。

由于我使用 Android Paging3 进行分页。将加载初始数据。 但问题是当我单击电影或系列按钮时,我需要使用新参数和起始页码重新启动 PagingSource。 但是在 viewmodel 中调用分页源不会触发任何事情。

我需要一种使用新参数调用 pagingSource 的方法,以便在发生分页之后,应该使用这些参数来完成。

我的寻呼源

    class MoviePagingSource(
    private val searchQuery: String,
    private val searchType : String,
    private val movieRepository: MovieRepository
) : PagingSource<Int , Movie>() {

    private val INITIAL_PAGE = Constants.INITIAL_PAGE_NUMBER

    override fun getRefreshKey(state: PagingState<Int, Movie>): Int? {
        return state.anchorPosition?.let {
            state.closestPageToPosition(it)?.prevKey?.plus(1) ?: state.closestPageToPosition(it)?.nextKey?.minus(1)
        }
    }

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Movie> {
        return try {
            val position = params.key ?: INITIAL_PAGE
            val response = movieRepository.searchMovie(searchQuery , position , searchType)
            val endOfPaginationReached = (response.data?.result == null)

            LoadResult.Page(
                data = response.data!!.result,
                prevKey = if(position == INITIAL_PAGE) null else position.minus(1),
                nextKey = if (endOfPaginationReached) null else position.plus(1)
            )
        }catch (e : Exception){
            LoadResult.Error(e)
        }
    }
}

这里的 searchQuery 和 searchType 参数是要改变的。 因此,每当更改时,我都需要调用新的寻呼源。 那就是问题所在

分页存储库

class MoviePagingRepository @Inject constructor(
    private val movieRepository: MovieRepository
    ) {

    private var pagingConfig : PagingConfig

    init {
        pagingConfig = PagingConfig(pageSize = Constants.PAGE_SIZE , maxSize = Constants.MAX_PAGE_COUNT)
    }

    fun getMovies(searchQuery: String, movieType : String, )
    :LiveData<PagingData<Movie>> {
        return Pager(config = pagingConfig , pagingSourceFactory = {MoviePagingSource(searchQuery , movieType , movieRepository)}).liveData
    }
}

视图模型

class HomeViewModel @Inject constructor(
    private val moviePagingRepository: MoviePagingRepository,
    private val movieRepository: MovieRepository
) : ViewModel(){

    var movieList : LiveData<PagingData<Movie>> = MutableLiveData()

    fun searchMovie(searchQuery : String , movieType : String) {
        movieList = moviePagingRepository.getMovies(searchQuery , movieType)
    }
}

主要活动

   override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_home)

        init()
    }


    private fun init(){

        movieViewModel = ViewModelProvider(this)[HomeViewModel::class.java]

        movieAdapter = MovieAdapter(movieViewModel)

        movies_recyclerview.apply {
            layoutManager = GridLayoutManager(context , Constants.COLUMN_COUNT)
            setHasFixedSize(true)
            adapter = movieAdapter.withLoadStateFooter(
                footer = LoaderAdapter()
            )
        }

        //This triggers the paging
        searchMovie(currentSearchQuery, currentMovieType)

        //This observes.
        observeViewModels()

    }

        private fun searchMovie(searchQuery : String , movieType : String){
        movieViewModel.searchMovie(searchQuery ,  movieType)
    }

    private fun observeViewModels(){

        movieViewModel.movieList.observe(this) {
            movieAdapter.submitData(lifecycle, it)
        }

        //This is triggered when I click on any movie type ( series , movie etc.)
       // This triggers the viewmodel method again. but apparently nothing happens
        movieViewModel.getMovieType().observe(this) { movieType ->
            searchMovie(currentSearchQuery,  currentMovieType)
        }
    }
}

有人可以帮忙吗,因为我对 paging3 比较陌生,这似乎很混乱。 adapter.refresh() 或 adapter.retry() 似乎都不适用于新变量。 任何形式的建议或改进将不胜感激。 谢谢

【问题讨论】:

    标签: android kotlin android-paging-3


    【解决方案1】:

    不要在活动的 init() 函数中调用 searchMovie 函数。这样,您在配置更改时一次又一次地调用该函数。 在您的 viewModel 中,添加此代码 ->

    val movieQueryParams = MutableLiveData(Pair("Your initial search query here","Your initial movie type here"))  
    val movieList = movieQueryParams.switchMap { (searchQuery,movieType)->
       // call your movie repository function here 
    }.cachedIn(viewModelScope) 
    
    fun onSearchQuerySubmit(query: String){
      movieQueryParams.first = query  
    }
    fun onMovieTypeSubmit(movieType: String) {
      movieQueryParams.second = movieType
    }
    

    每次用户输入新查询或单击新电影类型时,您都会从您的活动中调用 onSeachQuerySubmit() 和 onMovieTypeSubmit() 方法。
    编辑:顺便说一句,一种更简洁的方法也有助于处理进程死亡等问题,即切换到 kotlin 流而不是 livedata

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-12
      • 2020-11-16
      • 2022-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-08
      相关资源
      最近更新 更多