• Paging 实现加载更多


    1. 基于 保存图片到相册 修改添加

    保存图片到相册https://blog.csdn.net/u011193452/article/details/127065427

    2. 新增引用库

    1. dependencies {
    2. def paging_version = "3.1.1"
    3. implementation "androidx.paging:paging-runtime:$paging_version"
    4. // alternatively - without Android dependencies for tests
    5. testImplementation "androidx.paging:paging-common:$paging_version"
    6. //retrofit网络请求库
    7. implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    8. implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    9. }

    3. 第一种方式,使用 Paging2, API 已过时

      3.1 实现 PageKeyedDataSource 文件 PixabayDataSources.kt

    1. class PixabayDataSources(private val context: Context) : PageKeyedDataSource<Int, PhotoItem>() {
    2. private val queryKey =
    3. arrayOf("cat", "beauty", "car", "dog", "phone", "computer", "flower", "animal")
    4. private var keyValue = ""
    5. //Initial 最初
    6. override fun loadInitial(
    7. params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, PhotoItem>
    8. ) {
    9. keyValue = queryKey.random()
    10. val url = "https://pixabay.com/api/?key=30070990-cfc31c9f778ceeef4009d910d&q=${keyValue}&per_page=30&page=1"
    11. StringRequest(
    12. Request.Method.GET,
    13. url,
    14. {
    15. val dataList = Gson().fromJson(it, Pixabay::class.java).hits.toList()
    16. callback.onResult(dataList, null, 2)
    17. },
    18. {
    19. Log.e("MyTag", "loadInitial: $it")
    20. }
    21. ).also {
    22. VolleySingleton.getInstance(context).requestQueue.add(it)
    23. }
    24. }
    25. override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, PhotoItem>) {
    26. val url =
    27. "https://pixabay.com/api/?key=30070990-cfc31c9f778ceeef4009d910d&q=${keyValue}&per_page=30&page=${params.key}"
    28. StringRequest(
    29. Request.Method.GET,
    30. url,
    31. {
    32. val dataList = Gson().fromJson(it, Pixabay::class.java).hits.toList()
    33. callback.onResult(dataList, params.key + 1)
    34. },
    35. {
    36. Log.e("MyTag", "loadAfter: $it")
    37. }
    38. ).also {
    39. VolleySingleton.getInstance(context).requestQueue.add(it)
    40. }
    41. }
    42. override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, PhotoItem>) {
    43. }
    44. }

      3.2 实现 DataSource.Factory, PixabayDataSourceFactory.kt

    1. class PixabayDataSourceFactory(private val context: Context) : DataSource.Factory<Int, PhotoItem>() {
    2. override fun create(): DataSource<Int, PhotoItem> {
    3. return PixabayDataSources(context)
    4. }
    5. }

      3.4 修改 ViewModel, GalleryViewModel.kt

    1. class GalleryViewModel(application: Application) : AndroidViewModel(application) {
    2. val pagedListLiveData = PixabayDataSourceFactory(application).toLiveData(1)
    3. fun resetQuery() {
    4. pagedListLiveData.value?.dataSource?.invalidate()
    5. }
    6. }

      3.5 修改继承 ListAdapter 为 PagedListAdapter,修改判空

      3.6 调用 GalleryFragment.kt

    1. class GalleryFragment : Fragment() {
    2. private lateinit var binding: FragmentGalleryBinding
    3. private lateinit var galleryAdapter:GalleryAdapter
    4. private val galleryViewModel by viewModels()
    5. override fun onCreateView(
    6. inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    7. ): View? {
    8. binding = FragmentGalleryBinding.inflate(inflater, container, false)
    9. return binding.root
    10. }
    11. override fun onOptionsItemSelected(item: MenuItem): Boolean {
    12. when (item.itemId) {
    13. R.id.swipeIndicator -> {
    14. binding.swipeLayoutGallery.isRefreshing = true
    15. Handler().postDelayed({
    16. galleryViewModel.resetQuery()
    17. }, 300)
    18. }
    19. }
    20. return super.onOptionsItemSelected(item)
    21. }
    22. //加载菜单栏
    23. override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
    24. super.onCreateOptionsMenu(menu, inflater)
    25. inflater.inflate(R.menu.menu, menu)
    26. }
    27. override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    28. super.onViewCreated(view, savedInstanceState)
    29. setHasOptionsMenu(true)
    30. galleryAdapter = GalleryAdapter()
    31. binding.recyclerView?.apply {
    32. adapter = galleryAdapter
    33. //GridLayouStaager(requireContext(), 2) 对齐 StaggeredGridLayoutManager 交错感
    34. layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
    35. }
    36. viewModel()
    37. }
    38. private fun viewModel(){
    39. galleryViewModel.pagedListLiveData.observe(viewLifecycleOwner, Observer {
    40. galleryAdapter.submitList(it)
    41. binding.swipeLayoutGallery.isRefreshing = false
    42. })
    43. binding.swipeLayoutGallery.setOnRefreshListener {
    44. galleryViewModel.resetQuery()
    45. }
    46. }
    47. }

    4. 第二种方式 使用 Paging3 加载分页,retrofit2 进行 Http 请求

      4.1 定义实体类,在 Pixabay.kt 中添加

    1. class PixabayResponse {
    2. val hits: List = emptyList()
    3. val total = 0
    4. val totalHits = 0
    5. }

      4.2 实现 Api 服务请求 ApiService.kt

    1. //https://pixabay.com/api/?key=30070990-cfc31c9f778ceeef4009d910d&q=beauty&per_page=30&page=1
    2. const val key = "30070990-cfc31c9f778ceeef4009d910d"
    3. interface ApiService {
    4. @GET("?key=$key")
    5. suspend fun queryPixabay(@Query("q") queryKey : String, @Query("page") page: Int, @Query("per_page") perPage: Int): PixabayResponse
    6. companion object {
    7. private const val BASE_URL = "https://pixabay.com/api/"
    8. fun create(): ApiService {
    9. return Retrofit.Builder()
    10. .baseUrl(BASE_URL)
    11. .addConverterFactory(GsonConverterFactory.create())
    12. .build()
    13. .create(ApiService::class.java)
    14. }
    15. }
    16. }

      4.3 实现 PagingSource ,PixabayDataSources.kt 中添加

    1. class PixabayPagingSource(private val apiService: ApiService) : PagingSource<Int, PhotoItem>() {
    2. private val queryKey = arrayOf("cat", "beauty", "car", "dog", "phone", "computer", "flower", "animal")
    3. private var key = queryKey.random()
    4. override fun getRefreshKey(state: PagingState<Int, PhotoItem>): Int? {
    5. key = queryKey.random();
    6. return null
    7. }
    8. override suspend fun load(params: LoadParams<Int>): LoadResult<Int, PhotoItem> {
    9. return try {
    10. val page = params.key ?: 1
    11. val pageSize = params.loadSize
    12. val repoResponse = apiService.queryPixabay(key, page, pageSize)
    13. val repoItems = repoResponse.hits
    14. val prevKey = if (page > 1) page - 1 else null
    15. val nextKey = if (repoItems.isNotEmpty()) page + 1 else null
    16. Log.i("MyTag", "page: $page pageSize: $pageSize prevKey: $prevKey nextKey: $nextKey")
    17. LoadResult.Page(repoItems, prevKey, nextKey)
    18. } catch (e: Exception) {
    19. LoadResult.Error(e)
    20. }
    21. }
    22. }

      4.4 添加 ViewModel,GalleryViewModel.kt

    1. //1. Repository中实现网络请求
    2. object Repository {
    3. private const val PAGE_SIZE = 10
    4. private val apiService = ApiService.create()
    5. fun getPagingData(): Flow> {
    6. // PagingConfig的一个参数prefetchDistance,用于表示距离底部多少条数据开始预加载,
    7. // 设置0则表示滑到底部才加载。默认值为分页大小。
    8. // 若要让用户对加载无感,适当增加预取阈值即可。 比如调整到分页大小的5倍
    9. return Pager(
    10. config = PagingConfig(pageSize = PAGE_SIZE, prefetchDistance = 2 * PAGE_SIZE),
    11. pagingSourceFactory = { PixabayPagingSource(apiService) }).flow
    12. }
    13. }
    14. class GalleryPagingViewModel : ViewModel() {
    15. fun getPagingData(): Flow> {
    16. return Repository.getPagingData().cachedIn(viewModelScope)
    17. }
    18. }

      4.5 修改继承 ListAdapter 为 PagingDataAdapter, currentList 为 snapshot(),修改判空

      4.6 调用 GalleryFragment.kt

    1. class GalleryFragment : Fragment() {
    2. private lateinit var binding: FragmentGalleryBinding
    3. private lateinit var galleryAdapter:GalleryAdapter
    4. private val galleryPagingViewModel by viewModels()
    5. override fun onCreateView(
    6. inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    7. ): View? {
    8. binding = FragmentGalleryBinding.inflate(inflater, container, false)
    9. return binding.root
    10. }
    11. override fun onOptionsItemSelected(item: MenuItem): Boolean {
    12. when (item.itemId) {
    13. R.id.swipeIndicator -> {
    14. binding.swipeLayoutGallery.isRefreshing = true
    15. Handler().postDelayed({
    16. galleryAdapter.refresh()
    17. }, 300)
    18. }
    19. }
    20. return super.onOptionsItemSelected(item)
    21. }
    22. //加载菜单栏
    23. override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
    24. super.onCreateOptionsMenu(menu, inflater)
    25. inflater.inflate(R.menu.menu, menu)
    26. }
    27. override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    28. super.onViewCreated(view, savedInstanceState)
    29. setHasOptionsMenu(true)
    30. galleryAdapter = GalleryAdapter()
    31. binding.recyclerView?.apply {
    32. adapter = galleryAdapter
    33. //GridLayouStaager(requireContext(), 2) 对齐 StaggeredGridLayoutManager 交错感
    34. layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
    35. }
    36. pagingViewModel()
    37. }
    38. private fun pagingViewModel() {
    39. lifecycleScope.launch {
    40. galleryPagingViewModel.getPagingData().collect {
    41. galleryAdapter.submitData(it)
    42. binding.swipeLayoutGallery.isRefreshing = false
    43. }
    44. }
    45. binding.swipeLayoutGallery.setOnRefreshListener {
    46. galleryAdapter.refresh()
    47. }
    48. }
    49. }

    5. 展示图

  • 相关阅读:
    再玩玩B端搭建
    1024程序员节与我的“摆烂“选择
    SpringBoot拦截器Interceptor的使用-基础篇
    linux系统编程6-守护进程、线程
    Nginx模块开发之http handler实现流量统计(入门篇)
    QT—3D绘图
    用文字描述给黑白照上色,这个免费网站火了!网友:比其他同类都好用
    Spring获取bean对象
    Zookeeper重要概念
    【008】将多个捕获文件进行合并
  • 原文地址:https://blog.csdn.net/u011193452/article/details/127108132