![](/img/trans.png)
[英]Android architecture components paging DataSource.Factory error
[英]How to fix android architecture components paging onItemAtEndLoaded get in loop?
我正在嘗試練習android架構組件分頁
帶有 Room、MVVM 和 LiveData 的本地 + 遠程數據源
當我第一次滾動列表(獲取遠程數據)時,它通過 PagedList.BoundaryCallback 中的onItemAtEndLoaded進入循環,但下次打開活動時它會平滑滾動(獲取本地數據)
這是我的GitHub的鏈接在這里!
誰能幫我看看如何解決它,謝謝!
活動
class PagingActivity : AppCompatActivity() {
lateinit var viewModel: PagingViewModel
lateinit var adapter: PagingAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_paging)
val factory = PagingViewModelFactory(PagingRepository(), application)
viewModel = ViewModelProviders.of(this,factory).get(PagingViewModel::class.java)
adapter = PagingAdapter()
recyclerView.adapter = adapter
viewModel.pagedListLiveData.observe(this, Observer {
adapter.submitList(it)
})
}
}
視圖模型
class PagingViewModel(repository: PagingRepository, application: Application) :
AndroidViewModel(application) {
val pagedListLiveData = repository.getDataItem(application)
}
存儲庫
class PagingRepository : PagingRepositoryCallback {
private lateinit var localDataSource: DataSource.Factory<Int, DataItem>
override fun getDataItem(application: Application): LiveData<PagedList<DataItem>> {
val pagedListLiveData: LiveData<PagedList<DataItem>> by lazy {
localDataSource = DataItemDbHelper(application).getRoomDataItemDao().getAllDataItem()
val config = PagedList.Config.Builder()
.setPageSize(25)
.setEnablePlaceholders(false)
.build()
LivePagedListBuilder(localDataSource, config)
.setBoundaryCallback(PagingBoundaryCallback(application))
.build()
}
return pagedListLiveData
}
}
interface PagingRepositoryCallback {
fun getDataItem(application: Application): LiveData<PagedList<DataItem>>
}
邊界回調
class PagingBoundaryCallback(context: Context) :
PagedList.BoundaryCallback<DataItem>() {
private var page = 2
private val api = AllPlayerApi.api
private val dao = DataItemDbHelper(context).getRoomDataItemDao()
override fun onZeroItemsLoaded() {
super.onZeroItemsLoaded()
api.getAllPlayer().enqueue(createWebserviceCallback())
}
override fun onItemAtEndLoaded(itemAtEnd: DataItem) {
super.onItemAtEndLoaded(itemAtEnd)
api.getAllPlayer(page).clone().enqueue(createWebserviceCallback())
}
private fun createWebserviceCallback(): Callback<AllPlayerData> {
return object : Callback<AllPlayerData> {
override fun onFailure(call: Call<AllPlayerData>?, t: Throwable?) {
Log.d("Huang", " get player fail ")
}
override fun onResponse(call: Call<AllPlayerData>?, response: Response<AllPlayerData>) {
Log.d("Huang", " onResponse " + page)
response.body()!!.data!!.forEach {
it.imageUrl = "https://pdc.princeton.edu/sites/pdc/files/events/new-nba-logo-1.png"
}
insertItemsIntoDb(response)
page++
}
}
}
private fun insertItemsIntoDb(response: Response<AllPlayerData>) {
GlobalScope.launch {
response.body()!!.data!!.forEach {
dao.insert(it)
}
}
}
}
邏輯為,如果onItemAtEndLoaded
得到相同的itemAtEnd
,則什么都不做。
var lastItemAtEnd:DataItem? = null
override fun onItemAtEndLoaded(itemAtEnd: DataItem) {
lastItemAtEnd?.timestamp?.apply{
if(itemAtEnd.timestamp==this){
return;
}
}
super.onItemAtEndLoaded(itemAtEnd)
api.getAllPlayer(page).clone().enqueue(createWebserviceCallback())
}
由於您的頁面大小為 25,因此頁面列表配置應將setInitialLoadSizeHint 設置為 25,以避免循環/不必要地調用onItemAtEndLoaded方法
val config = PagedList.Config.Builder()
.setPageSize(25)
.setInitialLoadSizeHint(25) //same as your page size
.setEnablePlaceholders(false)
.build()
我知道這已經很長時間了,但我只是發布解決方案以備不時之需。
您應該為您的適配器注冊一個觀察者並監聽onItemRangeInserted
事件,如果項目范圍的起始位置為零,只需將適配器滾動到零位置,這將使您的RecyclerView
在第一次加載時保持在零位置,順便說一下,您應該設置setPrefetchDistance
值小於setInitialLoadSizeHint
。 這是適配器觀察者的 Java 代碼
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
if(positionStart == 0)
recyclerView.scrollToPosition(positionStart);
}
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.