赞
踩
准备好接口
- package com.example.android_learn_paging.net
-
- import com.example.android_learn_paging.model.NetDataList
- import retrofit2.http.GET
- import retrofit2.http.Query
-
- interface FeedBackApi {
- @GET("api/v1/open/test")
- suspend fun getFeedBack(
- @Query("page") page: Int,
- @Query("size") size: Int
- ): NetDataList
- }
用laravel8.5 写的 就是对数据库进行分页查询
- public function index($size, $search): JsonResponse
- {
- $res = AppFeedBack::query();
- if ($search) {
- if (isset($search['app_name'])) {
- $res = $res->where('app_name', 'like', "%" . $search['app_name'] . "%");
- }
- if (isset($search['content'])) {
- $res = $res->where('content', 'like', "%" . $search['content'] . "%");
- }
- }
- $data = $res
- ->orderBy('create_time', 'desc')
- ->paginate($size)
- ->toArray();
-
- // return AppFeedBack::simplePaginate(15);
-
- return $this->apiSuccess("", $data);
- }
大概给大家看下工程结构
很复杂。
返回的数据bean格式如下
- package com.example.android_learn_paging.model
-
- data class FeedBack(
- val id: Int, val app_name: String, val package_name: String, val content: String
- )
-
- data class FeedBacks(
- val current_page: Int, val data: ArrayList<FeedBack>, val last_page: Int
-
- )
-
- data class NetDataList(
- val code: Int, val message: String, val data: FeedBacks
- )
api接口
- package com.example.android_learn_paging.net
-
- import com.example.android_learn_paging.model.NetDataList
- import retrofit2.http.GET
- import retrofit2.http.Query
-
- interface FeedBackApi {
- @GET("api/v1/open/test")
- suspend fun getFeedBack(
- @Query("page") page: Int,
- @Query("size") size: Int
- ): NetDataList
- }
初始化数据类
- package com.example.android_flow_practice.net
-
- import android.util.Log
- import okhttp3.OkHttpClient
- import okhttp3.logging.HttpLoggingInterceptor
- import retrofit2.Retrofit
- import retrofit2.converter.gson.GsonConverterFactory
- import retrofit2.create
-
- object RetrofitClient {
- val url = "https://xxx.xxxx.xxxx";
- private const val TAG = "RetrofitClient"
-
- private val instance: Retrofit by lazy {
- val interceptor = HttpLoggingInterceptor(HttpLoggingInterceptor.Logger {
- Log.w(TAG, "${it}")
- })
-
- interceptor.level = HttpLoggingInterceptor.Level.BODY;
-
- Retrofit.Builder().client(
- OkHttpClient.Builder().addInterceptor(interceptor).build()
- ).baseUrl(url)
- .addConverterFactory(GsonConverterFactory.create())
- .build()
- }
-
-
- fun <T> createApi(clazz: Class<T>): T {
- return instance.create(clazz) as T
- }
- }
用到了三方依赖
-
- implementation "androidx.activity:activity-ktx:1.5.1"
- implementation "androidx.fragment:fragment-ktx:1.5.2"
-
- implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
-
- implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
-
- implementation "com.squareup.retrofit2:retrofit:2.9.0"
- implementation "com.squareup.retrofit2:converter-gson:2.9.0"
- implementation "com.squareup.okhttp3:logging-interceptor:3.4.1"
-
- implementation "androidx.paging:paging-runtime-ktx:3.1.1"
- implementation "com.squareup.picasso:picasso:2.71828"
这俩勾上 kapt加上
好了
继续
AppConfigs
- package com.example.android_learn_paging.config
-
- object AppConfigs {
- const val LOAD_PAGE = 8
-
- //默认就是3倍
- const val INITPAGE_SIZE = LOAD_PAGE * 3
- }
paging3 的一次加载页数 。这里写死了。为啥要这么写 因为后面就知道了
核心adapter PageSource
FeedBackPagingSource
- package com.example.android_learn_paging.paging
-
- import android.util.Log
- import androidx.paging.PagingSource
- import androidx.paging.PagingState
- import com.example.android_flow_practice.net.RetrofitClient
- import com.example.android_learn_paging.config.AppConfigs
- import com.example.android_learn_paging.model.FeedBack
- import com.example.android_learn_paging.net.FeedBackApi
- import kotlinx.coroutines.delay
-
- class FeedBackPagingSource : PagingSource<Int, FeedBack>() {
- private val TAG = "FeedBackPagingSource"
-
- /**
- * 1 8
- * 2 8
- * 3 8
- *
- *
- * null 2
- * 1 3
- * 2 4
- *
- *
- * 1 24
- * 2 8
- * 3 8
- *
- *
- * null 4
- * 3 5
- * 4 6
- */
- override suspend fun load(params: LoadParams<Int>): LoadResult<Int, FeedBack> {
- val currentPage = params.key ?: 1
- val pageSize = params.loadSize
- val feedbacks =
- RetrofitClient.createApi(FeedBackApi::class.java).getFeedBack(currentPage, pageSize)
-
- Log.d(TAG, "load: currentPage $currentPage ,pageSize $pageSize")
-
-
- var prevKey: Int? = null
- var nextKey: Int? = null
- if (currentPage == 1) {
- prevKey = null
- nextKey = AppConfigs.INITPAGE_SIZE / AppConfigs.LOAD_PAGE + 1
- } else {
- prevKey = currentPage - 1
- nextKey =
- if (feedbacks.data.last_page > feedbacks.data.current_page) currentPage + 1 else null
- }
-
-
-
-
-
-
- return try {
- LoadResult.Page(data = feedbacks.data.data, prevKey = prevKey, nextKey = nextKey)
- } catch (e: Exception) {
- e.printStackTrace()
- return LoadResult.Error(e)
- }
-
- }
-
- override fun getRefreshKey(state: PagingState<Int, FeedBack>): Int? {
- return null
- }
-
- }
由于第一次加载了三页数 所以再次加载不可以直接从2开始
这个注释上面是指的
第一次 加载8个 对应下面 首次加载为null 然后下一页为2
第二次 8个 对应下面 第二次 加载 上一页为 1 然后下一页为3 、
这都是理想情况下 当如果是分页首次加载了 initialLoadSize 为默认3倍的时候要处理就往下面数
就懂了
viewModel记录了我们在如何处理这个数据 并且返回了FLow
- package com.example.android_learn_paging.viewmodel
-
- import androidx.lifecycle.ViewModel
- import androidx.lifecycle.viewModelScope
- import androidx.paging.Pager
- import androidx.paging.PagingConfig
- import androidx.paging.PagingData
- import androidx.paging.cachedIn
- import com.example.android_learn_paging.config.AppConfigs
- import com.example.android_learn_paging.model.FeedBack
- import com.example.android_learn_paging.paging.FeedBackPagingSource
- import kotlinx.coroutines.flow.Flow
- class FeedBackViewModel : ViewModel() {
- private val moives by lazy {
- Pager(config = PagingConfig(
- pageSize = AppConfigs.LOAD_PAGE,
- initialLoadSize = AppConfigs.INITPAGE_SIZE,
- prefetchDistance = 1
- ), pagingSourceFactory = { FeedBackPagingSource() }).flow.cachedIn(viewModelScope)
- }
- fun loadFeedBack(): Flow<PagingData<FeedBack>> = moives
- }
下面就是页面代码了。
先 MainActivity吧
- package com.example.android_learn_paging.activity
-
- import androidx.appcompat.app.AppCompatActivity
- import android.os.Bundle
- import androidx.activity.viewModels
- import androidx.lifecycle.lifecycleScope
- import androidx.paging.LoadState
- import com.example.android_learn_paging.adapter.FeedBackAdapter
- import com.example.android_learn_paging.adapter.MovieLoadMoreAdapter
- import com.example.android_learn_paging.databinding.ActivityMainBinding
- import com.example.android_learn_paging.viewmodel.FeedBackViewModel
- import kotlinx.coroutines.flow.collectLatest
-
- class MainActivity : AppCompatActivity() {
-
- private val feedBackViewModel: FeedBackViewModel by viewModels()
-
- private val mBinding: ActivityMainBinding by lazy {
- ActivityMainBinding.inflate(layoutInflater)
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(mBinding.root)
-
- val feedBackAdapter = FeedBackAdapter(this)
-
- mBinding.apply {
- rv.adapter =
- feedBackAdapter.withLoadStateFooter(MovieLoadMoreAdapter(this@MainActivity))
-
- swipeRefreshLayout.setOnRefreshListener {
- feedBackAdapter.refresh()
-
- }
- }
-
- lifecycleScope.launchWhenCreated {
- feedBackViewModel.loadFeedBack().collectLatest {
- feedBackAdapter.submitData(it)
- }
- }
-
- lifecycleScope.launchWhenCreated {
- feedBackAdapter.loadStateFlow.collectLatest { status ->
- mBinding.swipeRefreshLayout.isRefreshing = status.refresh is LoadState.Loading
- }
- }
- }
- }
布局
- <?xml version="1.0" encoding="utf-8"?>
- <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".activity.MainActivity">
-
- <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
- android:id="@+id/swipeRefreshLayout"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
-
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/rv"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
- </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
-
- </androidx.constraintlayout.widget.ConstraintLayout>
看到了很多生代码 没关系 一点一点补充
FeedBackAdapter.kt
- package com.example.android_learn_paging.adapter
-
- import android.content.Context
- import android.view.LayoutInflater
- import android.view.ViewGroup
- import androidx.paging.PagingDataAdapter
- import androidx.recyclerview.widget.DiffUtil
- import com.example.android_learn_paging.databinding.ItemPagingBinding
- import com.example.android_learn_paging.model.FeedBack
-
- val diffUtil = object : DiffUtil.ItemCallback<FeedBack>() {
- //如果id一样 就认为是同一个元素
- override fun areContentsTheSame(oldItem: FeedBack, newItem: FeedBack): Boolean {
- return oldItem.id == newItem.id
- }
-
- override fun areItemsTheSame(oldItem: FeedBack, newItem: FeedBack): Boolean {
- return oldItem == newItem
- }
- }
-
- class FeedBackAdapter(private val context: Context) :
- PagingDataAdapter<FeedBack, BindingViewHolder>(diffUtil) {
- override fun onBindViewHolder(holder: BindingViewHolder, position: Int) {
- val feedBack = getItem(position)
- feedBack?.let {
- val binding = holder.binding as ItemPagingBinding
- binding.feedback = it
- binding.packageName = "https://www.baidu.com/s?wd=%E7%99%BE%E5%BA%A6%E7%83%AD%E6%90%9C&sa=ire_dl_gh_logo_texing&rsv_dl=igh_logo_pc";
- }
- }
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingViewHolder {
- // val binding = Pagint
- val binding = ItemPagingBinding.inflate(LayoutInflater.from(context), parent, false)
- return BindingViewHolder(binding)
- }
- }
BindingViewHolder
- package com.example.android_learn_paging.adapter
-
- import androidx.recyclerview.widget.RecyclerView
- import androidx.viewbinding.ViewBinding
- class BindingViewHolder(val binding: ViewBinding) : RecyclerView.ViewHolder(binding.root) {}
ImageViewBindingAdapter
对app:image标签来进行注解
- package com.example.android_learn_paging.adapter
-
- import android.graphics.Color
- import com.example.android_learn_paging.R
- import android.text.TextUtils
- import android.widget.ImageView
- import androidx.databinding.BindingAdapter
- import com.squareup.picasso.Picasso
-
- class ImageViewBindingAdapter {
-
-
- companion object {
- @JvmStatic
- @BindingAdapter("image")
- fun setImage(imageView: ImageView, url: String) {
- if (!TextUtils.isEmpty(url)) {
- Picasso.get().load(url).placeholder(R.drawable.ic_launcher_background)
- .into(imageView)
- } else {
- imageView.setBackgroundColor(Color.GRAY)
- }
- }
- }
-
- }
下拉加载更多组件
MovieLoadMoreAdapter
- package com.example.android_learn_paging.adapter
-
- import android.content.Context
- import android.view.LayoutInflater
- import android.view.ViewGroup
- import androidx.paging.LoadState
- import androidx.paging.LoadStateAdapter
- import com.example.android_learn_paging.databinding.FeedbackLoadmoreBinding
-
- class MovieLoadMoreAdapter(private val context: Context) : LoadStateAdapter<BindingViewHolder>() {
- override fun onBindViewHolder(holder: BindingViewHolder, loadState: LoadState) {
-
- }
-
- override fun onCreateViewHolder(parent: ViewGroup, loadState: LoadState): BindingViewHolder {
- val binding = FeedbackLoadmoreBinding.inflate(LayoutInflater.from(context), parent, false)
- return BindingViewHolder(binding)
- }
- }
adapter非常简单
feedback_loadmore.xml
- <?xml version="1.0" encoding="utf-8"?>
- <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="50dp"
- android:padding="10dp">
-
- <ProgressBar
- android:id="@+id/progressBar"
- android:layout_width="20dp"
- android:layout_height="20dp"
- android:layout_marginStart="20dp"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent" />
-
- <TextView
- android:id="@+id/tv_loading"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="加载更多数据"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="@id/progressBar" />
-
- </androidx.constraintlayout.widget.ConstraintLayout>
adapter item布局
item_paging.xml
- <?xml version="1.0" encoding="utf-8"?>
- <layout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools">
-
- <data>
-
- <variable
- name="packageName"
- type="String" />
-
- <variable
- name="feedback"
- type="com.example.android_learn_paging.model.FeedBack" />
- </data>
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/tv_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="20dp"
- android:text="@{feedback.app_name}"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
- <TextView
- android:id="@+id/tv_context"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="10dp"
- android:text="@{feedback.content}"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/tv_name" />
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="10dp"
- app:image="@{packageName}"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/tv_context" />
-
- </androidx.constraintlayout.widget.ConstraintLayout>
- </layout>
系统的adapter指向一个上滑加载更多
下拉刷新用的是
检测刷新状态 并且刷新代码
是的
PagingDataAdapter 有自己的刷新代码。。而我是刚知道。。我以前都去刷新
他 先通过一个成员变量引用出来 然后调用
.invalidate()
进行刷新 也是可行的。。。但是不知道会不会有什么潜在问题。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。