Paging 实现加载更多

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

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

2. 新增引用库

dependencies {
    def paging_version = "3.1.1"
    implementation "androidx.paging:paging-runtime:$paging_version"
    // alternatively - without Android dependencies for tests
    testImplementation "androidx.paging:paging-common:$paging_version"

    //retrofit网络请求库
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
}

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

  3.1 实现 PageKeyedDataSource 文件 PixabayDataSources.kt

class PixabayDataSources(private val context: Context) : PageKeyedDataSource<Int, PhotoItem>() {
    private val queryKey =
        arrayOf("cat", "beauty", "car", "dog", "phone", "computer", "flower", "animal")
    private var keyValue = ""
    //Initial 最初
    override fun loadInitial(
        params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, PhotoItem>
    ) {
        keyValue = queryKey.random()
        val url = "https://pixabay.com/api/?key=30070990-cfc31c9f778ceeef4009d910d&q=${keyValue}&per_page=30&page=1"
        StringRequest(
            Request.Method.GET,
            url,
            {
                val dataList = Gson().fromJson(it, Pixabay::class.java).hits.toList()
                callback.onResult(dataList, null, 2)
            },
            {
                Log.e("MyTag", "loadInitial: $it")
            }
        ).also {
             VolleySingleton.getInstance(context).requestQueue.add(it)
        }
    }

    override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, PhotoItem>) {
        val url =
            "https://pixabay.com/api/?key=30070990-cfc31c9f778ceeef4009d910d&q=${keyValue}&per_page=30&page=${params.key}"
        StringRequest(
            Request.Method.GET,
            url,
            {
                val dataList = Gson().fromJson(it, Pixabay::class.java).hits.toList()
                callback.onResult(dataList, params.key + 1)
            },
            {
                Log.e("MyTag", "loadAfter: $it")
            }
        ).also {
            VolleySingleton.getInstance(context).requestQueue.add(it)
        }
    }

    override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, PhotoItem>) {
    }
}

  3.2 实现 DataSource.Factory, PixabayDataSourceFactory.kt

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

  3.4 修改 ViewModel, GalleryViewModel.kt

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

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

  3.6 调用 GalleryFragment.kt

class GalleryFragment : Fragment() {
    private lateinit var binding: FragmentGalleryBinding
    private lateinit var galleryAdapter:GalleryAdapter
    private val galleryViewModel by viewModels<GalleryViewModel>()

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View? {
        binding = FragmentGalleryBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.swipeIndicator -> {
                binding.swipeLayoutGallery.isRefreshing = true
                Handler().postDelayed({
                    galleryViewModel.resetQuery()
                }, 300)

            }
        }
        return super.onOptionsItemSelected(item)
    }

    //加载菜单栏
    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        super.onCreateOptionsMenu(menu, inflater)
        inflater.inflate(R.menu.menu, menu)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        setHasOptionsMenu(true)
        galleryAdapter = GalleryAdapter()

        binding.recyclerView?.apply {
            adapter = galleryAdapter
            //GridLayouStaager(requireContext(), 2) 对齐 StaggeredGridLayoutManager 交错感
            layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
        }
        viewModel()
    }  

    private fun viewModel(){
        galleryViewModel.pagedListLiveData.observe(viewLifecycleOwner, Observer {
            galleryAdapter.submitList(it)
            binding.swipeLayoutGallery.isRefreshing = false
        })
        binding.swipeLayoutGallery.setOnRefreshListener {
            galleryViewModel.resetQuery()
        }
    }
}

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

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

class PixabayResponse {
    val hits: List<PhotoItem> = emptyList()
    val total = 0
    val totalHits = 0
}

  4.2 实现 Api 服务请求 ApiService.kt

//https://pixabay.com/api/?key=30070990-cfc31c9f778ceeef4009d910d&q=beauty&per_page=30&page=1
const val key = "30070990-cfc31c9f778ceeef4009d910d"
interface ApiService {
    @GET("?key=$key")
    suspend fun queryPixabay(@Query("q") queryKey : String, @Query("page") page: Int, @Query("per_page") perPage: Int): PixabayResponse

    companion object {
        private const val BASE_URL = "https://pixabay.com/api/"
        fun create(): ApiService {
            return Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build()
                .create(ApiService::class.java)
        }
    }
}

  4.3 实现 PagingSource ,PixabayDataSources.kt 中添加

class PixabayPagingSource(private val apiService: ApiService) : PagingSource<Int, PhotoItem>() {
    private val queryKey = arrayOf("cat", "beauty", "car", "dog", "phone", "computer", "flower", "animal")
    private var key = queryKey.random()

    override fun getRefreshKey(state: PagingState<Int, PhotoItem>): Int? {
        key = queryKey.random();
        return null
    }

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, PhotoItem> {
        return try {
            val page = params.key ?: 1
            val pageSize = params.loadSize
            val repoResponse = apiService.queryPixabay(key, page, pageSize)
            val repoItems = repoResponse.hits
            val prevKey = if (page > 1) page - 1 else null
            val nextKey = if (repoItems.isNotEmpty()) page + 1 else null
            Log.i("MyTag", "page: $page  pageSize: $pageSize prevKey: $prevKey  nextKey: $nextKey")
            LoadResult.Page(repoItems, prevKey, nextKey)
        } catch (e: Exception) {
            LoadResult.Error(e)
        }
    }
}

  4.4 添加 ViewModel,GalleryViewModel.kt

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

class GalleryPagingViewModel : ViewModel() {
    fun getPagingData(): Flow<PagingData<PhotoItem>> {
        return Repository.getPagingData().cachedIn(viewModelScope)
    }
}

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

  4.6 调用 GalleryFragment.kt

class GalleryFragment : Fragment() {
    private lateinit var binding: FragmentGalleryBinding
    private lateinit var galleryAdapter:GalleryAdapter
    private val galleryPagingViewModel by viewModels<GalleryPagingViewModel>()

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View? {
        binding = FragmentGalleryBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.swipeIndicator -> {
                binding.swipeLayoutGallery.isRefreshing = true
                Handler().postDelayed({
                galleryAdapter.refresh()
                }, 300)

            }
        }
        return super.onOptionsItemSelected(item)
    }

    //加载菜单栏
    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        super.onCreateOptionsMenu(menu, inflater)
        inflater.inflate(R.menu.menu, menu)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        setHasOptionsMenu(true)
        galleryAdapter = GalleryAdapter()

        binding.recyclerView?.apply {
            adapter = galleryAdapter
            //GridLayouStaager(requireContext(), 2) 对齐 StaggeredGridLayoutManager 交错感
            layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
        }
       
        pagingViewModel()
    }

    private fun pagingViewModel() {
       lifecycleScope.launch {
            galleryPagingViewModel.getPagingData().collect {
                galleryAdapter.submitData(it)
                binding.swipeLayoutGallery.isRefreshing = false
            }
        }
        binding.swipeLayoutGallery.setOnRefreshListener {
            galleryAdapter.refresh()
        }
    }
}

5. 展示图

猜你喜欢

转载自blog.csdn.net/u011193452/article/details/127108132