Android Paging3/Page3 Cursor query segment photo into 3 grid RecyclerView,kotlin (2)

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

Android Paging 3 Flow or LiveData,kotlin(1)_zhangphil的博客-CSDN博客【代码】Android Paging 3,kotlin(1)https://blog.csdn.net/zhangphil/article/details/130735753

基于Android官方Paging Library的RecyclerView分页加载框架_android setmainthreadexecutor_zhangphil的博客-CSDN博客基于Android官方Paging Library的RecyclerView分页加载框架我之前写了一篇RecyclerView分页加载机制的文章,是基于Android官方的AsyncListUtil实现的,详情见附录文章1。现在再介绍一种RecyclerView分页加载框架:Android Paging Library。Android Paging Library是Android官方supporthttps://blog.csdn.net/zhangphil/article/details/78627332

猜你喜欢

转载自blog.csdn.net/zhangphil/article/details/130751993