Android Paging3/Page3 Cursor query segment photo into 3 grid RecyclerView,kotlin (2)
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
def paging_version = "3.1.1"
implementation "androidx.paging:paging-runtime:$paging_version"
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
implementation 'com.github.bumptech.glide:glide:4.15.1'
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.asLiveData
import androidx.lifecycle.get
import androidx.lifecycle.viewModelScope
import androidx.paging.LoadState
import androidx.paging.cachedIn
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
class MainActivity : AppCompatActivity() {
companion object {
val TAG = "paging-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
val liveData =
MyDataFlow.getPagingData(this).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"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" />
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
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)
val image: ImageView = itemView.findViewById(R.id.image)
}
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 data = getItem(position)
if (data != null) {
holder.page.text = "page=${data.page}"
holder.in_page_pos.text = "${data.inPagePos}/${data.pageSize}"
Glide.with(holder.itemView.context).load(data.path).into(holder.image)
}
}
}
<?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="130dp"
android:orientation="vertical"
android:padding="1dp">
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="80dp"
android:scaleType="centerCrop"
android:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/page"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="0" />
<TextView
android:id="@+id/in_page_pos"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="0/0" />
</LinearLayout>
import java.util.UUID
data class MyData(
val id: UUID,
val page: Int,
val inPagePos: Int,
val pageSize: Int,
val path: String?
)
import android.content.Context
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import kotlinx.coroutines.flow.Flow
object MyDataFlow {
const val PAGE_SIZE = 5
const val INIT_LOAD_SIZE = PAGE_SIZE
private val myLoadDataService = MyLoadDataService.create()
fun getPagingData(ctx: Context): Flow<PagingData<MyData>> {
return Pager(
config = PagingConfig(
initialLoadSize = INIT_LOAD_SIZE, //程序启动第1次load的第1页数据的数量,不是页数
pageSize = PAGE_SIZE, //每一次分页加载的数量,不是页数
prefetchDistance =PAGE_SIZE * 2, //距离底部多少条时候启动预加载,若做到用户滑动无感知,可以将此值设置的大些,比如PAGE_SIZE的n倍。
enablePlaceholders = true,
maxSize = Int.MAX_VALUE
),
pagingSourceFactory = { MyPagingDataSource(ctx, myLoadDataService) }
).flow
}
}
import android.content.Context
import android.database.Cursor
import android.provider.MediaStore
import android.util.Log
import java.util.UUID
class MyLoadDataService {
suspend fun loadData(ctx: Context, page: Int, perPage: Int): ArrayList<MyData> {
Log.d(MainActivity.TAG, "-> $page - $perPage")
val cursor: Cursor? = ctx.contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null,
null,
null,
null
)
Log.d(MainActivity.TAG, "总数=${cursor?.count}")
cursor?.moveToNext()
cursor?.moveToPosition((page - 1) * perPage)
Log.d(MainActivity.TAG, "cursor move to position = ${cursor?.position}")
Log.d(MainActivity.TAG, "moveToNext start $page - $perPage")
val items: ArrayList<MyData> = ArrayList()
for (i in 1..perPage) {
//图片的路径
val path = cursor?.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA))
val myData = MyData(UUID.randomUUID(), page, i, perPage, path)
items.add(myData)
cursor?.moveToNext()
}
Log.d(MainActivity.TAG, "moveToNext end $page - $perPage")
cursor?.close()
Log.d(MainActivity.TAG, "<- $page - $perPage")
return items
}
companion object {
fun create(): MyLoadDataService {
return MyLoadDataService()
}
}
}
import android.content.Context
import androidx.paging.PagingSource
import androidx.paging.PagingState
class MyPagingDataSource(
private val ctx: Context,
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 items: ArrayList<MyData> = myLoadDataService.loadData(ctx, page, pageSize)
val prevKey = if (page > 1) page - 1 else null
val nextKey = if (items.isNotEmpty()) page + 1 else null
LoadResult.Page(items, prevKey, nextKey)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
override fun getRefreshKey(state: PagingState<Int, MyData>): Int? {
return 0
}
}