1. Pading
1). 簡介
分頁庫使您可以更輕松地在應(yīng)用程序的RecyclerView中逐步和優(yōu)雅地加載數(shù)據(jù)暖途。許多應(yīng)用程序使用包含大量項目的數(shù)據(jù)源中的數(shù)據(jù)苍柏,但一次只顯示一小部分荤西。分頁庫可幫助您的應(yīng)用觀察并顯示此數(shù)據(jù)的合理子集。 此功能有幾個優(yōu)點:
數(shù)據(jù)請求消耗的網(wǎng)絡(luò)帶寬更少承粤,系統(tǒng)資源更少校坑。 擁有計量或小數(shù)據(jù)計劃的用戶會欣賞這些具有數(shù)據(jù)意識的應(yīng)用程序。
即使在數(shù)據(jù)更新和刷新期間函匕,應(yīng)用程序仍會繼續(xù)快速響應(yīng)用戶輸入娱据。
2). 依賴
ext {
paging_version = "1.0.0-alpha6"
}
dependencies {
// paging
implementation "android.arch.paging:runtime:$paging_version"
implementation("android.arch.paging:rxjava2:1.0.0-rc1") {
exclude group: 'android.arch.paging', module: 'common'
}
}
3). DataSource
- PageKeyedDataSource: 如果您加載的頁面嵌入了下一個/上一個鍵,請使用PageKeyedDataSource盅惜。 例如中剩,如果您從網(wǎng)絡(luò)中獲取社交媒體帖子忌穿,則可能需要將nextPage令牌從一個加載傳遞到后續(xù)加載。
- ItemKeyedDataSource: 如果需要使用項目N中的數(shù)據(jù)來獲取項目N + 1结啼,請使用ItemKeyedDataSource掠剑。 例如,如果您要為討論應(yīng)用程序提取線程注釋郊愧,則可能需要傳遞最后一條注釋的ID以獲取下一條注釋的內(nèi)容朴译。
- PositionalDataSource: 如果需要從數(shù)據(jù)存儲中選擇的任何位置獲取數(shù)據(jù)頁,請使用PositionalDataSource属铁。 此類支持從您選擇的任何位置開始請求一組數(shù)據(jù)項眠寿。 例如,請求可能返回以位置1200開頭的20個數(shù)據(jù)項红选。
2. Paging + Room
1). 創(chuàng)建Room數(shù)據(jù)實體
/**
* Room 實體
* Created by mazaiting on 2018/7/25.
*/
@Entity(tableName = "student")
data class StudentRoom(
var name: String
) {
@PrimaryKey(autoGenerate = true)
var id: Int = 0
}
2). 創(chuàng)建數(shù)據(jù)庫DAO
/**
* 數(shù)據(jù)庫操作對象
* Created by mazaiting on 2018/7/26.
*/
@Dao
interface StudentDao {
/**
* 插入數(shù)據(jù)
*/
@Insert
fun insert(student: List<StudentRoom>)
/**
* 查詢所有學(xué)生
*/
@Query("SELECT * FROM student ORDER BY id DESC")
fun findAllStudents() : DataSource.Factory<Int, StudentRoom>
}
3). 創(chuàng)建數(shù)據(jù)庫
/**
* 數(shù)據(jù)庫
* Created by mazaiting on 2018/7/26.
*/
@Database(entities = arrayOf(StudentRoom::class), version = 1)
abstract class StudentDatabase : RoomDatabase() {
// 獲取DAO
abstract fun studentDao() : StudentDao
}
4). 創(chuàng)建ViewModel
class StudentViewModel : ViewModel() {
/**
* 查詢所有學(xué)生
*/
fun findAllStudents(application: Application): LiveData<PagedList<StudentRoom>> {
val db = Room.databaseBuilder(application, StudentDatabase::class.java, "PAGING").build()
val dao = db.studentDao()
// val list: LiveData<PagedList<StudentRoom>> =
// LivePagedListBuilder(dao.findAllStudents(), 15).build()
val list: LiveData<PagedList<StudentRoom>> =
LivePagedListBuilder(dao.findAllStudents(),
PagedList.Config.Builder()
// 設(shè)置分頁加載數(shù)量
.setPageSize(PAGE_SIZE)
// 配置是否啟動PlaceHolders
.setEnablePlaceholders(ENABLE_PLACE_HOLDERS)
// 初始化加載數(shù)量
.setInitialLoadSizeHint(PAGE_SIZE)
.build()
).build()
return list
}
}
5). 創(chuàng)建RecycleView適配器
/**
* Student適配器
* Created by mazaiting on 2018/7/26.
*/
class StudentAdapter : PagedListAdapter<StudentRoom, StudentAdapter.StudentViewHolder>(DIFF_CALLBACK) {
override fun onBindViewHolder(holder: StudentViewHolder, position: Int) =
holder.bindTo(getItem(position))
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StudentViewHolder =
StudentViewHolder(parent)
companion object {
// Item回調(diào)
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<StudentRoom>() {
// 條目是否相同
override fun areItemsTheSame(oldItem: StudentRoom, newItem: StudentRoom): Boolean = oldItem.id == newItem.id
// 內(nèi)容是否相同
override fun areContentsTheSame(oldItem: StudentRoom, newItem: StudentRoom): Boolean = oldItem == newItem
}
}
class StudentViewHolder(parent: ViewGroup) : RecyclerView.ViewHolder(
// 加載布局
LayoutInflater.from(parent.context).inflate(R.layout.item_student, parent, false)
) {
// 查找view
private val nameView = itemView.findViewById<TextView>(R.id.tv_name)
// 創(chuàng)建數(shù)據(jù)
private var student: StudentRoom? = null
/**
* 綁定數(shù)據(jù)
*/
fun bindTo(student: StudentRoom?) {
this.student = student
// 設(shè)置文本
nameView.text = student?.name
}
}
}
6). Activity代碼
class PagingRoomActivity : AppCompatActivity() {
/**
* 懶加載ViewModel
*/
private val viewModel by lazy {
ViewModelProviders.of(this).get(StudentViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_paging_room)
// 創(chuàng)建適配器
val adapter = StudentAdapter()
// 設(shè)置布局管理者
rv_show.layoutManager = LinearLayoutManager(this)
// 設(shè)置適配器
rv_show.adapter = adapter
// 數(shù)據(jù)變化時更新列表
viewModel.findAllStudents(application).observe(this, Observer { adapter.submitList(it) })
}
}
3. Pading + 自定義數(shù)據(jù)源
1). 創(chuàng)建數(shù)據(jù)實體類
/**
* 數(shù)據(jù)實體類
* Created by mazaiting on 2018/7/26.
*/
data class Student (
val id: Int,
val name: String
)
2). 創(chuàng)建適配器
/**
* 適配器
* Created by mazaiting on 2018/7/26.
*/
class StudentAdapter : PagedListAdapter<Student, StudentAdapter.StudentViewHolder>(DIFF_CALLBACK) {
override fun onBindViewHolder(holder: StudentViewHolder, position: Int) =
holder.bindTo(getItem(position))
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StudentViewHolder =
StudentViewHolder(parent)
companion object {
/**
* 條目不同回調(diào)
*/
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Student>() {
override fun areItemsTheSame(oldItem: Student, newItem: Student): Boolean = oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: Student, newItem: Student): Boolean = oldItem == newItem
}
}
class StudentViewHolder(parent: ViewGroup) : RecyclerView.ViewHolder(
// 加載布局
LayoutInflater.from(parent.context).inflate(R.layout.item_student, parent, false)
) {
// 獲取view
private val nameView = itemView.findViewById<TextView>(R.id.tv_name)
private var student: Student? = null
/**
* 綁定數(shù)據(jù)
*/
fun bindTo(student: Student?) {
this.student = student
nameView.text = student?.name
}
}
}
3). 創(chuàng)建數(shù)據(jù)源
private val CHEESE_DATA = arrayListOf(
"Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
"Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
"Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese",
"Ami du Chambertin", "Anejo Enchilado", "Anneau du Vic-Bilh", "Anthoriro", "Appenzell",
"Aragon", "Ardi Gasna", "Ardrahan", "Armenian String", "Aromes au Gene de Marc",
"Asadero", "Asiago", "Aubisque Pyrenees", "Autun", "Avaxtskyr", "Baby Swiss",
"Babybel", "Baguette Laonnaise", "Bakers", "Baladi", "Balaton", "Bandal", "Banon",
"Barry's Bay Cheddar", "Basing", "Basket Cheese", "Bath Cheese", "Bavarian Bergkase",
"Baylough", "Beaufort", "Beauvoorde", "Beenleigh Blue", "Beer Cheese", "Bel Paese",
"Bergader", "Bergere Bleue", "Berkswell", "Beyaz Peynir", "Bierkase", "Bishop Kennedy",
"Blarney", "Bleu d'Auvergne", "Bleu de Gex", "Bleu de Laqueuille",
"Bleu de Septmoncel", "Bleu Des Causses", "Blue", "Blue Castello", "Blue Rathgore",
"Blue Vein (Australian)", "Blue Vein Cheeses", "Bocconcini", "Bocconcini (Australian)"
)
/**
* 數(shù)據(jù)源
* Created by mazaiting on 2018/7/26.
*/
class StudentDataSource : PositionalDataSource<Student>() {
/**
* 范圍加載
*/
override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback<Student>) {
// 回調(diào)結(jié)果
callback.onResult(loadRangeInternal(params.startPosition, params.loadSize))
}
/**
* 加載初始化
*/
override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback<Student>) {
// 全部數(shù)據(jù)數(shù)量
val totalCount = computeCount()
// 當(dāng)前位置
val position = computeInitialLoadPosition(params, totalCount)
// 加載數(shù)量
val loadSize = computeInitialLoadSize(params, position, totalCount)
// 回調(diào)結(jié)果
callback.onResult(loadRangeInternal(position, loadSize), position, totalCount)
}
/**
* 加載網(wǎng)絡(luò)數(shù)據(jù)
*/
private fun loadRangeInternal(position: Int, loadSize: Int): MutableList<Student> {
// 創(chuàng)建列表
val list = arrayListOf<Student>()
// 遍歷列表數(shù)據(jù)
CHEESE_DATA.mapIndexed { index, text -> list.add(Student(index, text)) }
// 設(shè)置加載數(shù)據(jù)
var size = loadSize
// 判斷加載的位置是否大于總數(shù)據(jù)
if (position >= computeCount()) {
// 返回空數(shù)據(jù)
return Collections.emptyList()
}
// 判斷總條數(shù)是否大于計算的數(shù)據(jù)
if (position + loadSize > computeCount()) {
size = computeCount() - position - 1
}
// L.e("${computeCount()}:: $position :: $size" )
// 返回子列表
return list.subList(position, size + position)
}
/**
* 總條數(shù)
*/
private fun computeCount(): Int = CHEESE_DATA.size
}
4). ViewModel中創(chuàng)建獲取數(shù)據(jù)方法
/**
* 查詢本地數(shù)據(jù)
*/
fun loadNativeStudent(): LiveData<PagedList<Student>> {
val dataSourceFactory = DataSource.Factory<Int, Student> { StudentDataSource() }
val list: LiveData<PagedList<Student>> =
LivePagedListBuilder(dataSourceFactory,
PagedList.Config.Builder()
.setPageSize(PAGE_SIZE)
.setEnablePlaceholders(ENABLE_PLACE_HOLDERS)
.setInitialLoadSizeHint(PAGE_SIZE)
.build()
).build()
return list
}
5). Activity代碼
class PagingCustomActivity : AppCompatActivity() {
/**
* 懶加載ViewModel
*/
private val viewModel by lazy {
ViewModelProviders.of(this).get(StudentViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_paging_custom)
// 創(chuàng)建適配器
val adapter = StudentAdapter()
// 設(shè)置布局管理者
rv_show.layoutManager = LinearLayoutManager(this)
// 設(shè)置適配器
rv_show.adapter = adapter
// 數(shù)據(jù)改變通知RecyclerView更新
viewModel.loadNativeStudent().observe(this, Observer { adapter.submitList(it) })
}
}