Architecture -- Paging

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) })
  }
}
6). 原文鏈接
7). 代碼下載
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末澜公,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子喇肋,更是在濱河造成了極大的恐慌,老刑警劉巖迹辐,帶你破解...
    沈念sama閱讀 212,332評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝶防,死亡現(xiàn)場離奇詭異,居然都是意外死亡明吩,警方通過查閱死者的電腦和手機间学,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,508評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來印荔,“玉大人低葫,你說我怎么就攤上這事∪月桑” “怎么了嘿悬?”我有些...
    開封第一講書人閱讀 157,812評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長水泉。 經(jīng)常有香客問我善涨,道長,這世上最難降的妖魔是什么草则? 我笑而不...
    開封第一講書人閱讀 56,607評論 1 284
  • 正文 為了忘掉前任钢拧,我火速辦了婚禮,結(jié)果婚禮上炕横,老公的妹妹穿的比我還像新娘源内。我一直安慰自己,他們只是感情好份殿,可當(dāng)我...
    茶點故事閱讀 65,728評論 6 386
  • 文/花漫 我一把揭開白布膜钓。 她就那樣靜靜地躺著塔鳍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪呻此。 梳的紋絲不亂的頭發(fā)上轮纫,一...
    開封第一講書人閱讀 49,919評論 1 290
  • 那天,我揣著相機與錄音焚鲜,去河邊找鬼掌唾。 笑死,一個胖子當(dāng)著我的面吹牛忿磅,可吹牛的內(nèi)容都是我干的糯彬。 我是一名探鬼主播,決...
    沈念sama閱讀 39,071評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼葱她,長吁一口氣:“原來是場噩夢啊……” “哼撩扒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起吨些,我...
    開封第一講書人閱讀 37,802評論 0 268
  • 序言:老撾萬榮一對情侶失蹤搓谆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后豪墅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體泉手,經(jīng)...
    沈念sama閱讀 44,256評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,576評論 2 327
  • 正文 我和宋清朗相戀三年偶器,在試婚紗的時候發(fā)現(xiàn)自己被綠了斩萌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,712評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡屏轰,死狀恐怖颊郎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情霎苗,我是刑警寧澤姆吭,帶...
    沈念sama閱讀 34,389評論 4 332
  • 正文 年R本政府宣布,位于F島的核電站叨粘,受9級特大地震影響猾编,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜升敲,卻給世界環(huán)境...
    茶點故事閱讀 40,032評論 3 316
  • 文/蒙蒙 一答倡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧驴党,春花似錦瘪撇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恕曲。三九已至,卻和暖如春渤涌,著一層夾襖步出監(jiān)牢的瞬間佩谣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,026評論 1 266
  • 我被黑心中介騙來泰國打工实蓬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留茸俭,地道東北人。 一個月前我還...
    沈念sama閱讀 46,473評論 2 360
  • 正文 我出身青樓安皱,卻偏偏與公主長得像调鬓,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子酌伊,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,606評論 2 350

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理腾窝,服務(wù)發(fā)現(xiàn),斷路器居砖,智...
    卡卡羅2017閱讀 134,637評論 18 139
  • 應(yīng)用開發(fā)者面臨的常見問題 共同的構(gòu)建原則 推薦應(yīng)用架構(gòu)構(gòu)建用戶界面獲取數(shù)據(jù)連接ViewModel和存儲庫緩存數(shù)據(jù)保...
    yyg閱讀 416評論 0 0
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時...
    歐辰_OSR閱讀 29,340評論 8 265
  • 丟掉50件不同種類的東西悯蝉,在3個月里归形,確實有助于整理生活吧,而后面半句純屬鼓勵鼻由。 這里就開始記錄: 1、舊衣服厚棵。最...
    綠楊煙外閱讀 550評論 0 3
  • 今天是寫做的第一天蕉世,萬事開頭難,嘿嘿婆硬。其實寫起來可能也沒那么難狠轻。 已經(jīng)開始上時間管理課程了,堅定了早上五點多起床的...
    周周的果子閱讀 227評論 0 0