Android - - - Paging3
生活随笔
收集整理的這篇文章主要介紹了
Android - - - Paging3
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Paging 庫可幫助您加載和顯示來自本地存儲或網絡中更大的數據集中的數據頁面。此方法可讓您的應用更高效地利用網絡帶寬和系統資源。Paging 庫的組件旨在契合推薦的?Android 應用架構,流暢集成其他?Jetpack?組件,并提供一流的 Kotlin 支持。
使用 Paging 庫的優勢
Paging 庫包含以下功能:
- 分頁數據的內存中緩存。該功能可確保您的應用在處理分頁數據時高效利用系統資源。
- 內置的請求重復信息刪除功能,可確保您的應用高效利用網絡帶寬和系統資源。
- 可配置的?RecyclerView?適配器,會在用戶滾動到已加載數據的末尾時自動請求數據。
- 對 Kotlin 協程和 Flow 以及?LiveData?和 RxJava 的一流支持。
- 內置對錯誤處理功能的支持,包括刷新和重試功能。
具體可移至Paging 庫概覽 ?|? Android 開發者 ?|? Android Developers (google.cn)查看具體作用。
一.以下主要講使用方式。
需求
1.導入依賴
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2'implementation "androidx.activity:activity-ktx:1.1.0"implementation "androidx.fragment:fragment-ktx:1.2.5"implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.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.0'implementation 'com.squareup.picasso:picasso:2.71828'implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'implementation 'com.google.code.gson:gson:2.8.6'2.創建數據實體類
data class Movies(@SerializedName("subjects")val movieList: List<Movie>,@SerializedName("has_more")val hasMore: Boolean ) data class Movie(val id: Int, val title: String, val rate: String, val cover: String)3.封裝Retrofit和定義數據源接口
?1.數據從本地服務獲取,所以接口是本地地址
object RetrofitClient {private val instance: Retrofit by lazy {val interceptor = HttpLoggingInterceptor(HttpLoggingInterceptor.Logger {Log.d("ning", it) //打印Log日志})interceptor.level = HttpLoggingInterceptor.Level.BODYRetrofit.Builder().client(OkHttpClient.Builder().addInterceptor(interceptor).build()).baseUrl("http://192.168.1.20:8080/pagingserver_war/").addConverterFactory(GsonConverterFactory.create()).build()}fun <T> createApi(clazz: Class<T>): T {return instance.create(clazz) as T} } interface MovieApi {@GET("pkds.do")suspend fun getMovies(@Query("page") page: Int, //當前第幾頁@Query("pagesize") pageSize: Int //每頁請求多少條數據): Movies }4.封裝ViewHolder和主adapter
class BindingViewHolder(val binding: ViewBinding) : RecyclerView.ViewHolder(binding.root) class MovieAdapter(private val context: Context) ://DiffUtil.ItemCallback 該回調會比較兩個條目是否是相同值,相同值不重新繪制PagingDataAdapter<Movie, BindingViewHolder>(object : DiffUtil.ItemCallback<Movie>() {//比較id是否相同override fun areItemsTheSame(oldItem: Movie, newItem: Movie): Boolean {return oldItem.id == newItem.id}//比較內容是否相同override fun areContentsTheSame(oldItem: Movie, newItem: Movie): Boolean {// kotlin === 引用 , == 內容// Java == 引用, equals 內容return oldItem == newItem}}) {/*override fun getItemViewType(position: Int): Int {return super.getItemViewType(position)}override fun getItemCount(): Int {return super.getItemCount()}*///此處用了DataBindingoverride fun onBindViewHolder(holder: BindingViewHolder, position: Int) {val movie = getItem(position)movie?.let {val binding = holder.binding as MovieItemBindingbinding.movie = itbinding.networkImage = it.cover}}override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingViewHolder {val binding = MovieItemBinding.inflate(LayoutInflater.from(context), parent, false)return BindingViewHolder(binding)} }5.圖片適配器與Paging加載更多適配器
//圖片適配器 class ImageViewBindingAdapter {//此處Picasso 是java代碼,而要使用他就要 java調用Kotlin代碼companion object {@JvmStatic //java調用kotlin靜態代碼需要加上該注解@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)}}}} 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 = MovieLoadmoreBinding.inflate(LayoutInflater.from(context), parent, false)return BindingViewHolder(binding)} }6.ViewMolder與PagingSource
class MovieViewModel : ViewModel() {// by lazy 用到時才會執行private val movies by lazy{Pager( //PagingConfig 定義一次從PagingSource加載的項數。config = PagingConfig(pageSize = 8 , //一頁取8個initialLoadSize = 16 ,//初始取一頁取16個//(這里有個Bug需要把initialLoadSize或prefetchDistance設大一點,預留位置更多的位置去加載數據)prefetchDistance = 1 //下滑還有 prefetchDistance條數據 時加載下一頁),//每頁都會調用一次,請求數據pagingSourceFactory = {MoviePagingSource()}//設置緩存flow 這里的 viewModelScope是根據activity生命周期的).flow.cachedIn( viewModelScope )}fun loadMovie() :Flow<PagingData<Movie>> = movies } class MoviePagingSource : PagingSource<Int, Movie>() {//currentPage 當前頁//prevKey 為當前頁的前一頁//nextKey 為當前頁的下一頁override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Movie> {delay(2000)val currentPage=params.key?:1 //當前頁的頁數val pageSize= params.loadSize //一頁多少條數據val movies = RetrofitClient.createApi(MovieApi::class.java).getMovies(currentPage, pageSize)var prevKey:Int?= null //var nextKey:Int? =nullval realPageSize = 8 //每一頁的數據加載條目val initilLoadSize=16 //初始頁的數據加載條目if(currentPage==1){prevKey=null //當前頁為第一頁的話,前一頁為0//你的初始頁的數據可能會比你之后獲取的每頁數據要多,為了保證你下一頁加載的數據是之前沒有加載過的數據。// 所以這里拿 初始頁數據數據量/每一頁加載的數據量+1,以保證你下次加載的數據是初始頁后面的數據nextKey=initilLoadSize/realPageSize+1;}else{prevKey=currentPage-1 //當前頁不是第一頁的話,前一頁為當前頁減一nextKey=if (movies.hasMore)currentPage+1 else null //當前頁有數據的話,下一頁就是,當前頁加一,反之為空}println("currentPage:$currentPage pageSize:$pageSize prevKey:$prevKey nextKey:$nextKey")//val prevKey:Int?=if (currentPage==1) null else currentPage-1//val nextKey:Int? =if (movies.hasMore)currentPage+1 else nullreturn try {LoadResult.Page(data = movies.movieList, //數據prevKey = prevKey, //prevKey 為當前頁的前一頁nextKey=nextKey //nextKey 為當前頁的下一頁)}catch (e :Exception){e.printStackTrace()return LoadResult.Error(e)}}override fun getRefreshKey(state: PagingState<Int, Movie>): Int? {return null}} }PagingSource下面的getRefreshKey函數返回null也可以,不影響執行。
7.MainActivity
class MainActivity : AppCompatActivity() {private val movieViewModel by viewModels<MovieViewModel>()private val mBinding: ActivityMainBinding by lazy {ActivityMainBinding.inflate(layoutInflater)}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(mBinding.root)val movieAdapter = MovieAdapter(this)mBinding.apply {//上拉加載適配器recyclerView.adapter=movieAdapter.withLoadStateFooter(MovieLoadMoreAdapter(this@MainActivity))//下拉刷新swipeRefreshLayout.setOnRefreshListener {movieAdapter.refresh()}}lifecycleScope.launchWhenCreated {movieViewModel.loadMovie().collectLatest {movieAdapter.submitData(it) //加載數據}}//下拉刷新的判斷lifecycleScope.launchWhenCreated {movieAdapter.loadStateFlow.collectLatest { start->mBinding.swipeRefreshLayout.isRefreshing=start.refresh is LoadState.Loading}}} }演示效果:
總結
以上是生活随笔為你收集整理的Android - - - Paging3的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【BMI指数计算器V3.0】项目实战
- 下一篇: nexus5 android 7.0,A