Android Paging 3 Flow or LiveData,kotlin(1)
android {
buildFeatures {
viewBinding = true
}
}
dependencies {
def paging_version = "3.1.1"
implementation "androidx.paging:paging-runtime:$paging_version"
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
}
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.get
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewModelScope
import androidx.paging.LoadState
import androidx.paging.cachedIn
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
companion object {
val TAG = "my-test"
}
private val viewModel by lazy { ViewModelProvider(this).get<MainViewModel>() }
private val myAdapter = MyAdapter()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
recyclerView.layoutManager = GridLayoutManager(this, 3).apply {
orientation = GridLayoutManager.VERTICAL
}
recyclerView.adapter = myAdapter
lifecycleScope.launch {
MyDataFlow.getPagingData().cachedIn(viewModel.viewModelScope).collect() { pagingData ->
myAdapter.submitData(pagingData)
}
}
/**或者
val liveData = MyDataFlow.getPagingData().cachedIn(viewModel.viewModelScope).asLiveData()
liveData.observe(this) {
myAdapter.submitData(lifecycle, it)
}
*/
myAdapter.addLoadStateListener {
when (it.refresh) {
is LoadState.NotLoading -> {
//recyclerView.visibility = View.VISIBLE
Log.d(TAG, "LoadState.NotLoading")
}
is LoadState.Loading -> {
//recyclerView.visibility = View.INVISIBLE
Log.d(TAG, "LoadState.Loading")
}
is LoadState.Error -> {
val state = it.refresh as LoadState.Error
Log.d(TAG, "LoadState.Error")
}
}
}
}
class MainViewModel : ViewModel() {
}
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
package my.application
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
class MyAdapter : PagingDataAdapter<MyData, MyAdapter.ViewHolder>(COMPARATOR) {
companion object {
private val COMPARATOR = object : DiffUtil.ItemCallback<MyData>() {
override fun areItemsTheSame(oldItem: MyData, newItem: MyData): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: MyData, newItem: MyData): Boolean {
return oldItem == newItem
}
}
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val page: TextView = itemView.findViewById(R.id.page)
val in_page_pos: TextView = itemView.findViewById(R.id.in_page_pos)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val repo = getItem(position)
if (repo != null) {
holder.page.text = "page=${repo.page}"
holder.in_page_pos.text = "${repo.inPagePos}/${repo.pageSize}"
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="120dp"
android:orientation="vertical">
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerInside"
android:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/page"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/in_page_pos"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
import java.util.UUID
data class MyData(
val id: UUID,
val page: Int,
val inPagePos: Int,
val pageSize: Int
)
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import kotlinx.coroutines.flow.Flow
object MyDataFlow {
private const val PAGE_SIZE = 50
private val myLoadDataService = MyLoadDataService.create()
fun getPagingData(): Flow<PagingData<MyData>> {
return Pager(
config = PagingConfig(
initialLoadSize = PAGE_SIZE * 2, //程序启动第1次load的第1页忠数据的数量
pageSize = PAGE_SIZE, //每一次分页加载的数量
prefetchDistance = PAGE_SIZE * 5, //距离底部多少条时候启动预加载,若做到用户滑动无感知,可以将此值设置的大些,比如PAGE_SIZE的n倍。
enablePlaceholders = true,
maxSize = Int.MAX_VALUE
),
pagingSourceFactory = { MyPagingDataSource(myLoadDataService) }
).flow
}
}
import android.util.Log
import java.util.UUID
class MyLoadDataService {
suspend fun loadData(page: Int, perPage: Int): ArrayList<MyData> {
Log.d(MainActivity.TAG, "$page - $perPage")
val items: ArrayList<MyData> = ArrayList()
for (i in 1..perPage) {
var r = MyData(UUID.randomUUID(), page, i, perPage)
items.add(r)
}
return items
}
companion object {
fun create(): MyLoadDataService {
return MyLoadDataService()
}
}
}
import androidx.paging.PagingSource
import androidx.paging.PagingState
class MyPagingDataSource(private val myLoadDataService: MyLoadDataService) :
PagingSource<Int, MyData>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MyData> {
return try {
val page = params.key ?: 1 // set page 1 as default
val pageSize = params.loadSize
var repoItems: ArrayList<MyData> = myLoadDataService.loadData(page, pageSize)
val prevKey = if (page > 1) page - 1 else null
val nextKey = if (repoItems.isNotEmpty()) page + 1 else null
LoadResult.Page(repoItems, prevKey, nextKey)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
override fun getRefreshKey(state: PagingState<Int, MyData>): Int? {
return 0
}
}