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()
}
}
}