老熟女激烈的高潮_日韩一级黄色录像_亚洲1区2区3区视频_精品少妇一区二区三区在线播放_国产欧美日产久久_午夜福利精品导航凹凸

重慶分公司,新征程啟航

為企業提供網站建設、域名注冊、服務器等服務

Paging庫怎么在Android中使用

這篇文章將為大家詳細講解有關Paging庫怎么在Android 中使用,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

10年積累的成都網站設計、成都做網站經驗,可以快速應對客戶對網站的新想法和需求。提供各種問題對應的解決方案。讓選擇我們的客戶得到更好、更有力的網絡服務。我雖然不認識你,你也不認識我。但先網站設計后付款的網站建設流程,更有枝江免費網站建設讓你可以放心的選擇與我們合作。

添加分頁依賴

按照如下代碼添加依賴:

dependencies {
  def paging_version = "1.0.0"

  implementation "android.arch.paging:runtime:$paging_version"

  // alternatively - without Android dependencies for testing
  testImplementation "android.arch.paging:common:$paging_version"

  // optional - RxJava support, currently in release candidate
  implementation "android.arch.paging:rxjava2:1.0.0-rc1"
}

備注: 分頁包幫助開發者在UI的列表容器中順暢地展示數據, 而不管是使用設備內部的數據庫還是從應用后端拉取數據.

庫架構

分頁庫的核心構件是PagedList類, 它是一個集合, 用于異步加載應用數據塊或者數據頁. 該類在應用的其它架構之間充當中介.

Data

每一個PagedList實例從DataSource中加載最新的應用數據. 數據從應用后端或者數據庫流入PagedList對象. 分頁包支持多樣的應用架構, 包括脫機數據庫和與后臺服務器通訊的數據庫.

UI

PagedList類通過PagedListAdapter加載數據項到RecyclerView里面. 在加載數據的時候, 這些類協同工作, 拉取數據并展示內容, 包括預取看不見的內容并在內容改變時加載動畫.

支持不同的數據架構

分頁包支持應用架構, 包括應用拉取數據的地方是從后臺服務器, 還是本機數據庫, 還是兩者的結合.

只有網絡

要展示后臺數據, 需要使用Retrofit的同步版本, 加載信息到自定義的DataSource對象中.
備注: 分頁包的DataSource對象并沒有提供任何錯誤處理機制, 因為不同的應用需要用不同的方式處理和展示UI錯誤. 如果錯誤發生了, 順從結果的回調, 然后稍后重試.

只有數據庫

要設置RecyclerView觀測本地存儲, 偏向于使用Room持久化庫. 用這種方式, 無論任何時候數據庫數據插入或者修改, 這些改變會自動地在負責展示這些數據的RecyclerView展示出來.

網絡+數據庫

在開始觀測數據庫之后, 你能夠通過使用PagedList.BoundaryCallback來監聽數據庫什么時候過期. 之后, 你可能從網絡拉取更多的數據, 并把它們插入到數據庫中. 如果UI正在展示數據庫, 以上就是你所需要做的全部.

下面的代碼片斷展示了BoundaryCallback的使用實例:

class ConcertViewModel {
  fun search(query: String): ConcertSearchResult {
    val boundaryCallback =
        ConcertBoundaryCallback(query, myService, myCache)
    // Error-handling not shown in this snippet.
    val networkErrors = boundaryCallback.networkErrors
  }
}

class ConcertBoundaryCallback(
    private val query: String,
    private val service: MyService,
    private val cache: MyLocalCache
) : PagedList.BoundaryCallback() {
  override fun onZeroItemsLoaded() {
    requestAndSaveData(query)
  }

  override fun onItemAtEndLoaded(itemAtEnd: Concert) {
    requestAndSaveData(query)
  }
}

處理網絡錯誤

在使用網絡拉取或者分頁的數據, 而這些數據正在使用分頁包展示的時候, 不總是把網絡分為要么"可用"要么"不可能"是很重要的, 因為許多連接是間歇性或者成片的:

  • 特定的服務器可能不能響應網絡請求;

  • 設備可能聯接了慢的或者弱的網絡;

應用應該檢查每一個請求是否成功, 并且在網絡不可用的情形下, 盡可能快地恢復. 比如, 你可以為用戶提供一個"重試"按鈕, 如果數據沒有刷新成功的話. 如果在數據分頁期間發生錯誤, 最好自動地重新分頁請求.

更新已有應用

如果應用已經從網絡或者數據庫消費數據, 很大可能可以直接升級到分頁庫提供的功能.

自定義分頁解決方案

如果你使用了自定義功能加載數據源中的小的數據集, 你可以使用PagedList類取代這個邏輯. PagedList類實例提供了內建的連接, 到通用的數據源. 這些實例也提供了在應用中引用的RecyclerView的適配器.

使用列表而非分頁加載的數據

如果你使用內存里的列表作為UI適配器的后備數據結構, 考慮使用PagedList類觀測數據更新, 如果列表中數據項變得很多的話. PagedList實例既可以使用LiveData也可以使用Observable對UI傳遞數據更新, 同時最小化了加載時間和內存使用. 然而, 應用中使用PagedList對象代替List并不要求對UI結構和數據更新邏輯作任何改變.

使用CursorAdapter將數據cursor與列表視圖聯系起來

應用也許會使用CursorAdapter將數據從Cursor跟ListView連接起來. 在這種情況下, 通常需要從ListView遷移到RecyclerView, 然后使用Room或者PositionalDataSource構件代替Cursor, 當然, 這主要依據于Cursor實例能否訪問SQLite數據庫.

在一些情況下, 比如使用Spinner實例的時候, 你僅僅提供了Adapter本身. 然后一個庫使用了加載進adapter中的數據, 并展示了數據. 在這些情況下, 把adapter數據類型轉化為LiveData, 之后在嘗試使用將這些數據項在UI中填充起來之前, 將這個列表在ArrayAdapter對象中包裹起來.

使用AsyncListUtil異步加載內容

如果你在使用AsyncListUtil對象異步地加載和展示分組信息的話, 分頁包將會使得加載數據更加方便:

  • 數據并不需要定位. 分頁包讓你直接從后臺使用網絡提供的鍵加載數據.

  • 數據量太大. 使用分頁包可以將數據加載分頁直到沒有任何數據留下.

  • 更方便地觀測數據. 分頁包能夠展示應用在可觀測數據結構中持有的ViewModel.

 數據庫例子

 使用LiveData觀測分頁數據

下面的示例代碼展示了所有一起工作的碎片. 當演唱會事件在數據庫中添加, 刪除或者修改的修改的時候, RecyclerView中的內容自動且高效地更新:

@Dao
interface ConcertDao {
  // The Integer type parameter tells Room to use a PositionalDataSource
  // object, with position-based loading under the hood.
  @Query("SELECT * FROM user ORDER BY concert DESC")
  fun concertsByDate(): DataSource.Factory
}

class MyViewModel(concertDao: ConcertDao) : ViewModel() {
  val concertList: LiveData> = LivePagedListBuilder(
      concertDao.concertsByDate(),
      /* page size */ 20
  ).build()
}

class MyActivity : AppCompatActivity() {
  public override fun onCreate(savedState: Bundle?) {
    super.onCreate(savedState)
    val viewModel = ViewModelProviders.of(this)
        .get(MyViewModel::class.java!!)
    val recyclerView = findViewById(R.id.concert_list)
    val adapter = ConcertAdapter()
    viewModel.concertList.observe(this, { pagedList ->
        adapter.submitList(pagedList) })
    recyclerView.setAdapter(adapter)
  }
}

class ConcertAdapter() :
    PagedListAdapter(DIFF_CALLBACK) {
  fun onBindViewHolder(holder: ConcertViewHolder, position: Int) {
    val concert = getItem(position)
    if (concert != null) {
      holder.bindTo(concert)
    } else {
      // Null defines a placeholder item - PagedListAdapter automatically
      // invalidates this row when the actual object is loaded from the
      // database.
      holder.clear()
    }
  }

  companion object {
    private val DIFF_CALLBACK = object : DiffUtil.ItemCallback() {
      // Concert details may have changed if reloaded from the database,
      // but ID is fixed.
      override fun areItemsTheSame(oldConcert: Concert,
          newConcert: Concert): Boolean =
          oldConcert.id == newConcert.id

      override fun areContentsTheSame(oldConcert: Concert,
          newConcert: Concert): Boolean =
          oldConcert == newConcert
    }
  }
}

使用RxJava2觀測分頁數據

如果你偏愛使用RxJava2而非LiveData, 那么你可以創建Observable或者Flowable對象:

 class MyViewModel(concertDao: ConcertDao) : ViewModel() {
   val concertList: Flowable> = RxPagedListBuilder(
       concertDao.concertsByDate(),
       /* page size */ 50
   ).buildFlowable(BackpressureStrategy.LATEST)
 }

之后你可以按照如下代碼開始和停止觀測數據:

class MyActivity : AppCompatActivity() {
  private lateinit var adapter: ConcertAdapter
  private lateinit var viewModel: MyViewModel

  private val disposable = CompositeDisposable()

  public override fun onCreate(savedState: Bundle?) {
    super.onCreate(savedState)
    val recyclerView = findViewById(R.id.concert_list)
    viewModel = ViewModelProviders.of(this).get(MyViewModel::class.java!!)
    adapter = ConcertAdapter()
    recyclerView.setAdapter(adapter)
  }

  override fun onStart() {
    super.onStart()
    disposable.add(viewModel.concertList.subscribe({
        flowableList -> adapter.submitList(flowableList)
    }))
  }

  override fun onStop() {
    super.onStop()
    disposable.clear()
  }
}

基于RxJava2解決方案的ConcertDao和ConcertAdapter代碼, 和基于LiveData解決方案的代碼是一樣的.

UI構件及其出發點

將UI和視圖模型聯接起來 

你可以按照如下方式, 將LiveData實例跟PagedListAdapter聯系起來:

private val adapter = ConcertPagedListAdapter()
private lateinit var viewModel: ConcertViewModel

override fun onCreate(savedInstanceState: Bundle?) {
  viewModel = ViewModelProviders.of(this)
      .get(ConcertViewModel::class.java)
  viewModel.concerts.observe(this, adapter::submitList)
}

當數據源提供一個新PagedList實例的時候, activity會將這些對象改善給adapter. PagedListAdapter實現, 定義了更新如何計算, 自動地處理分頁和列表不同. 由此, 你的ViewHolder只需要綁定到特定的提供項:

class ConcertPagedListAdapter() : PagedListAdapter(
    object : DiffUtil.ItemCallback() {
  // The ID property identifies when items are the same.
  override fun areItemsTheSame(oldItem: Concert, newItem: Concert)
      = oldItem.id = newItem.id

  // Use the "==" operator (or Object.equals() in Java-based code) to know
  // when an item's content changes. Implement equals(), or write custom
  // data comparison logic here.
  override fun areContentsTheSame(oldItem: Concert, newItem: Concert) =
      oldItem.name == newItem.name && oldItem.date == newItem.date
  }
) {
  override fun onBindViewHolder(holder: ConcertViewHolder, position: Int) {
    val concert: Concert? = getItem(position)

    // Note that "concert" is a placeholder if it's null
    holder.bind(concert)
  }
}

PagedListAdapter使用PagedList.Callback對象處理分頁加載事件. 當用戶滑動時, PagedListAdapter調用PagedList.loadAround()方法將從DataSource中拉聚攏數據項提示提供給基本的PagedList.
備注: PageList是內容不可變的. 這意味著, 盡管新內容能夠被加載到PagedList實例中, 但已加載項一旦加載完成便不能發生改變. 由此, 如果PagedList中的內容發生改變, PagedListAdapter對象將會接收到一個包含已更新信息的全新的PagedList.

實現diffing回調

先前的代碼展示了areContentsTheSame()的手動實現, 它比較了對象的相關的域. 你也可以使用Java中的Object.equals()方法或者Kotlin中的==操作符. 但是要確保要么實現了對象中的equals()方法或者使用了kotlin中的數據對象.

使用不同的adapter類型進行diffing

如果你選擇不從PagedListAdapter繼承--比如你在使用一個提供了自己的adapter的庫的時候--你依然可以通過直接使用AsyncPagedListDiffer對象使用分頁包adapter的diffing功能.

在UI中提供占位符

在應用完成拉取數據之前, 如果你想UI展示一個列表, 你可以向用戶展示占位符列表項. RecyclerView通過將列表項臨時地設置為null來處理這個情況.

備注: 默認情況下, 分頁包開啟了占位符行為.

占位符有如下好處:

  • 支持scrollbar. PagedList向PagedListAdapter提供了大量的列表項. 這個信息允許adapter繪制一個表示列表已滿的scrollbar. 當新的頁加載時, scrollbar并不會跳動, 因為列表是并不沒有改變它的size.

  • 不需要"正在加載"旋轉指針. 因為列表大小已知, 沒必要提醒用戶有更多的數據項正在加載. 占位符本身表達了這個信息.

在添加占位符的支持之前, 請牢記以下先置條件:

  • 要求集合中數據可數. 來自Room持久化庫的DataSource實例能夠高效地計算數據項. 然而, 如果你在用自定義本地存儲方案或者只有網絡的數據架構, 想了解數據集中有多少數據項可能代價很高, 甚至不可能.

  • 要求adapter負責未加載數據項. 你正在使用的adapter或者展示機制來準備填充列表, 需要處理null列表項. 比如, 當將數據綁定到ViewHolder的時候, 你需要提供默認值表示未加載數據.

  • 要求數據相同數量的item view. 如果列表項數目能夠基于內容發生改變, 比如, 社交網絡更新, 交叉淡入淡出看起來并不好. 在這種情況下, 強烈推薦禁掉占位符.

數據構件及其出發點

構建可觀測列表

通常情況下, UI代碼觀測LiveData對象(或者, 如果你在使用RxJava2, 是Flowable/Observable對象), 這個對象存在于應用的ViewModel中. 這個可觀測對象形成了應用列表數據內容和展示的連接.

要創建這么一個可觀測PagedList對象, 需要將DataSource.Factory實例傳給LivePageListBuilder/RxPagedListBuilder對象. 一個DataSource對象對單個PagedList加載分頁. 這個工廠類為內容更新創建PagedList實例, 比如數據庫表驗證, 網絡刷新等. Room持久化庫能夠提供DataSource.Factory, 或者自定義.

如下代碼展示了如何在應用的ViewModel類中使用Room的DataSource.Factory構建能力創建新的LiveData實例:

ConcertDao.kt:

interface ConcertDao {
   // The Integer type parameter tells Room to use a PositionalDataSource
   // object, with position-based loading under the hood.
   @Query("SELECT * FROM concerts ORDER BY date DESC")
   public abstract DataSource.Factory concertsByDate()
 }

ConcertViewModel.kt:

// The Integer type argument corresponds to a PositionalDataSource object.
val myConcertDataSource : DataSource.Factory =
    concertDao.concertsByDate()

val myPagedList = LivePagedListBuilder(myConcertDataSource, /* page size */ 20)
    .build()

定義分頁配置

要想為復雜情形更深入地配置LiveData, 你也可以定義自己的分頁配置. 尤其是, 你可以定義如下屬性:

  • 頁大小: 每一頁的數據量.

  • 預取距離: 給定UI中最后可見項, 超過該項之后多少項, 分頁包要嘗試提前提取數據. 這個值應該比page size大幾倍.

  • 占位符展示: 決定了UI是否會為還沒有完成加載的數據項展示占位符.

如果你想要對分布包從數據庫加載中設置更多的控件, 要像下面的代碼一樣, 傳遞自定義的Executor對象給LivePagedListBuilder:

EventViewModel.kt:

val myPagingConfig = PagedList.Config.Builder()
    .setPageSize(50)
    .setPrefetchDistance(150)
    .setEnablePlaceholders(true)
    .build()

// The Integer type argument corresponds to a PositionalDataSource object.
val myConcertDataSource : DataSource.Factory =
    concertDao.concertsByDate()

val myPagedList = LivePagedListBuilder(myConcertDataSource, myPagingConfig)
    .setFetchExecutor(myExecutor)
    .build()

選擇正確的數據源類型

連接更最好地處理源數據結構的數據源很重要:

  • 如果加載的頁嵌套了之前/之后頁的key的話, 使用PageKeyDataSource. 比如, 比如你正在從網絡中拉取社交媒體博客, 你也許需要傳遞從一次加載向下一次加載的nextPage token.

  • 如果需要使用每N項數據項的數據拉取每N+1項的話, 使用ItemKeyedDataSource. 比如, 你在為一個討論型應用拉取螺紋評論, 你可能需要傳遞最后一條評論的ID來獲取下一條評論的內容.

  • 如果你需要從數據商店中的任意位置拉取分頁數據的話, 使用PositionalDataSource. 這個類支持請求任意位置開始的數據集. 比如, 請求也許返回從位置1200開始的20條數據.

通知數據非法

在使用分頁包時, 在表或者行數據變得陳腐時, 取決于數據層來通知應用的其它層. 要想這么做的話, 需要從DataSource類中調用invalidate()方法.

備注: UI也可以使用"滑動刷新"模式來觸發數據非法功能.

構建自己的數據源

如果你使用了自定義的數據解決方案, 或者直接從網絡加載數據, 你可以實現一個DataSource子類. 下面的代碼展示了數據源從給定的concert起始時間切斷:

class ConcertTimeDataSource(private val concertStartTime: Date) :
    ItemKeyedDataSource() {
  override fun getKey(item: Concert) = item.startTime

  override fun loadInitial(
      params: LoadInitialParams,
      callback: LoadInitialCallback) {
    val items = fetchItems(concertStartTime, params.requestedLoadSize)
    callback.onResult(items)
  }

  override fun loadAfter(
      params: LoadParams,
      callback: LoadCallback) {
    val items = fetchItemsAfter(
      date = params.key,
      limit = params.requestedLoadSize)
    callback.onResult(items)
  }
}

通過創建真實的DataSource.Factory子類, 你之后能夠加載自定義的數據到PagedList對象. 下面的代碼展示了如何創建在之前代碼中定義的自定義數據源:

class ConcertTimeDataSourceFactory(private val concertStartTime: Date) :
    DataSource.Factory() {
  val sourceLiveData = MutableLiveData()
  override fun create(): DataSource {
    val source = ConcertTimeDataSource(concertStartTime)
    sourceLiveData.postValue(source)
    return source
  }
}

考慮內容更新

當你構建可觀測PagedList對象的時候, 考慮一下內容是如何更新的. 如果你直接從Room數據庫中加載數據, 更新會自動地推送到UI上面.

如果你在使用分頁的網絡API, 通常你會有用戶交互, 比如"滑動刷新", 把它作為信號去驗證當前DataSource非法并請求一個新的. 這個行為出行在下面的代碼中:

class ConcertActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    ...

    concertViewModel.refreshState.observe(this, Observer {
      swipeRefreshLayout.isRefreshing =
          it == NetworkState.LOADING
    })
    swipeRefreshLayout.setOnRefreshListener {
      concertViewModel.invalidateDataSource()
    }
  }
}

提供數據表現之間的映射

對于DataSource加載的數據, 分頁包支持基于數據項和基于頁的轉換.

下面的代碼中, concert名和日期的聯合被映射成包含姓名和日期的字符串:

class ConcertViewModel : ViewModel() {
  val concertDescriptions : LiveData>
    init {
      val factory = database.allConcertsFactory()
          .map { concert ->
              concert.name + " - " + concert.date
          }
      concerts = LivePagedListBuilder(factory, 30).build()
    }
  }
}

如果在數據加載之后, 想要包裹, 轉換或者準備item, 這將非常有用. 因為這個工作是在獲取執行器中完成的, 你可以在其中執行花銷巨大的工作, 比如, 從硬盤中讀取, 查詢數據庫等.

關于Paging庫怎么在Android 中使用就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。


當前文章:Paging庫怎么在Android中使用
轉載來源:http://www.xueling.net.cn/article/iigihd.html

其他資訊

在線咨詢
服務熱線
服務熱線:028-86922220
TOP
主站蜘蛛池模板: av成人资源| 国产精品v欧美精品 | 欧美日韩在线一区 | 性按摩xxxx| 国产学生av娇小av毛片 | 天堂色情无码WWW视频无码 | 168黄色网| 韩国理伦三级做爰在线播放 | 国内精品久久久久 | 国产精品久久久久久久久久久天堂 | 国产精品一品二区三区四区18 | 国产欧美另类久久久精品91区 | 一本色道久久88—综合亚洲精品 | 精品视频一区在线 | ASS年轻少妇BBWPIC | 久久久欧美国产精品人妻噜噜 | 911网站大全在线?看 | 大粗鳮巴征服少妇视频 | 国产精品成人av禁果av | 国产精品久久久久农村妇女 | 女人张开腿让男人桶个爽 | 亚洲人和日本人jzz视频 | 亚洲美免无码中文字幕 | 国产伦理一区二区三区 | 国产成人A人亚洲精V品无码 | 欧美麻豆久久久久久中文 | 视频一区视频二区中文字幕 | 777亚洲欧美日韩精品中文中字幕 | 高H猛烈失禁潮喷A片在线观看 | 亚洲一区二区三区含羞草 | 午夜成人看特AAAA片视频 | 麻豆久久久久 | 久久官网 | 视色在线视频 | 国产精品久久久久久无码不卡 | 麻豆高清免费国产一区 | 欧美乱妇狂野欧美在线视频 | 国产伦精品一区二区三区视频1 | 九月婷婷人人澡人人添人人爽 | 五月天综合婷婷欧美专区 | 欧洲免费看片尺码大 |