我尝试为我的应用程序实现分页库。我正在使用Livedata,RxJava和Retrofit2。在我的片段中包含分页功能。项目加载并很好地显示在recyclerview上,但是,当我调试pagedlist观察时,提交的列表计数为0。
这是我的以下代码。
BookDataSource类是抽象的。
abstract class BookDataSource: PageKeyedDataSource<Int, Book>() {
val state: MutableLiveData<NetworkState> = MutableLiveData()
private var retryCompletable: Completable? = null
abstract var compositeDisposable: CompositeDisposable
abstract var byblosRepo: ByblosRepo
override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, Book>) {
Log.i("LOAD", "initial")
updateState(NetworkState.LOADING)
loadInitialRequest(byblosRepo, params, callback)
}
override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, Book>) {
Log.i("LOAD", "after")
updateState(NetworkState.LOADING)
loadAfterRequest(byblosRepo, params, callback)
}
override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, Book>) {
Log.i("LOAD", "before")
}
fun retry() {
if (retryCompletable != null) {
compositeDisposable.add(retryCompletable!!
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe())
}
}
fun updateState(state: NetworkState) {
this.state.postValue(state)
}
fun setRetry(action: Action?) {
retryCompletable = if (action == null) null else Completable.fromAction(action)
}
abstract fun loadInitialRequest(byblosRepo: ByblosRepo, params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, Book>)
abstract fun loadAfterRequest(byblosRepo: ByblosRepo, params: LoadParams<Int>, callback: LoadCallback<Int, Book>)
}
这是真实的数据源类。
class AwardedBookDataSource constructor(private val awardType: String, override var byblosRepo: ByblosRepo, override var compositeDisposable: CompositeDisposable) : BookDataSource() {
override fun loadInitialRequest(byblosRepo: ByblosRepo, params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, Book>) {
val awardedQuery = AwardedBookRequest(awardType, ByblosApp.deviceId, "1", 0)
compositeDisposable.add(byblosRepo.getAwardedBook(awardedQuery)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ search ->
callback.onResult(search.books, 1, 2)
updateState(NetworkState.DONE)
}, { _ ->
updateState(NetworkState.ERROR)
setRetry(Action { loadInitial(params, callback) })
}))
}
override fun loadAfterRequest(byblosRepo: ByblosRepo, params: LoadParams<Int>, callback: LoadCallback<Int, Book>) {
val awardedQuery = AwardedBookRequest(awardType, ByblosApp.deviceId, params.key.toString(), 0)
compositeDisposable.add(byblosRepo.getAwardedBook(awardedQuery)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ search ->
callback.onResult(search.books, params.key + 1)
updateState(NetworkState.DONE)
}, { _ ->
updateState(NetworkState.ERROR)
setRetry(Action { loadAfter(params, callback) })
}))
}
}
这是抽象数据源工厂类。
abstract class BookDataSourceFactory: DataSource.Factory<Int, Book>() {
val bookDataSourceLiveData = MutableLiveData<BookDataSource>()
abstract var compositeDisposable: CompositeDisposable
abstract var byblosRepo: ByblosRepo
override fun create(): DataSource<Int, Book> {
val bookDataSource = createBookDataSource()
bookDataSourceLiveData.postValue(bookDataSource)
return bookDataSource
}
abstract fun createBookDataSource(): BookDataSource
}
实际数据源工厂类
class AwardedBookDataSourceFactory(override var byblosRepo: ByblosRepo, override var compositeDisposable: CompositeDisposable): BookDataSourceFactory() {
lateinit var awardType: String
override fun createBookDataSource(): BookDataSource = AwardedBookDataSource(awardType, byblosRepo, compositeDisposable)
}
我的片段视图模型
class PrixViewModel @Inject constructor(byblosRepo: ByblosRepo) : BaseViewModel() {
lateinit var awardedBookList: LiveData<PagedList<Book>>
private var bookDataSourceFactory: AwardedBookDataSourceFactory = AwardedBookDataSourceFactory(byblosRepo, compositeDisposable)
fun getBookList(awardType: String = "all") {
val config = PagedList.Config.Builder()
.setPageSize(20)
.setInitialLoadSizeHint(20)
.setEnablePlaceholders(false)
.build()
bookDataSourceFactory.awardType = awardType
awardedBookList = LivePagedListBuilder<Int, Book>(bookDataSourceFactory, config).build()
}
/*fun retry(tabPosition: Int) {
bookDataSourceFactory.bookDataSourceLiveData.value?.retry()
}*/
fun getState(): LiveData<NetworkState> = Transformations.switchMap<BookDataSource, NetworkState>(bookDataSourceFactory.bookDataSourceLiveData, BookDataSource::state)
fun listIsEmpty(): Boolean {
return awardedBookList.value?.isEmpty() ?: true
}
/*fun replaceSubscription(lifecycleOwner: LifecycleOwner, awardType: String) {
//awardedBookList.removeObservers(lifecycleOwner)
getBookList(awardType)
//bookDataSourceFactory.awardType = awardType
//bookDataSourceFactory.bookDataSourceLiveData.value?.invalidate()
}*/
}
这是我的片段,显示了recyclerview
PrixFragment类:BaseFragment(){
@Inject
lateinit var mPrixViewModelFactory: ViewModelFactory
override fun getBindingVariable(): Int = BR.viewModel
override fun getLayoutId(): Int = R.layout.fragment_prix
private lateinit var mFragmentPrixBinding: FragmentPrixBinding
private lateinit var prixListAdapter: PrixListAdapter
companion object {
fun newInstance(): PrixFragment {
val args = Bundle()
val fragment = PrixFragment()
fragment.arguments = args
return fragment
}
}
override fun getViewModel(): PrixViewModel = ViewModelProviders.of(this, mPrixViewModelFactory).get(PrixViewModel::class.java)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mFragmentPrixBinding = getViewDataBinding()
setUp()
getViewModel().getBookList()
initAdapter()
initState()
}
private fun initState() {
getViewModel().getState().observe(this, Observer { state ->
getViewModel().loadingVisibility.value = if (getViewModel().listIsEmpty() && state == NetworkState.LOADING) View.VISIBLE else View.GONE
if (!getViewModel().listIsEmpty()) {
prixListAdapter.setState(state ?: NetworkState.DONE)
}
})
}
private fun initAdapter() {
prixListAdapter = PrixListAdapter()
mFragmentPrixBinding.apply {
recyclerPrix.layoutManager = LinearLayoutManager(activity, RecyclerView.VERTICAL, false)
recyclerPrix.addItemDecoration(DividerItemDecoration(activity, RecyclerView.VERTICAL))
recyclerPrix.adapter = prixListAdapter
}
getViewModel().awardedBookList.observe(this, Observer {
//THIS "IT" LIST SIZE SHOWS 0 COUNT. Why? But recyclerview notified.
prixListAdapter.submitList(it)
})
}
private fun setUp() {
mFragmentPrixBinding.apply {
tabPrix.addTab(tabPrix.newTab())
tabPrix.addTab(tabPrix.newTab())
tabPrix.addTab(tabPrix.newTab())
tabPrix.addTab(tabPrix.newTab())
changeCurrentTabFont(0)
tabPrix.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabReselected(p0: TabLayout.Tab?) {}
override fun onTabUnselected(p0: TabLayout.Tab?) {}
override fun onTabSelected(tab: TabLayout.Tab) {
changeCurrentTabFont(tab.position)
var awardType = "all"
when (tab.position) {
0 -> awardType = "all"
1 -> awardType = "goncourt"
2 -> awardType = "femina"
3 -> awardType = "renaudot"
}
//viewModel?.replaceSubscription(this@PrixFragment, awardType)
viewModel?.getBookList(awardType)
initAdapter()
}
})
}
}
private fun changeCurrentTabFont(position: Int) {
for (i in 0 until mFragmentPrixBinding.tabPrix.tabCount) {
val tab: TabLayout.Tab? = mFragmentPrixBinding.tabPrix.getTabAt(i)
tab?.customView = null
if (position != i)
tab?.customView = getTabView(resources.getStringArray(R.array.tab_titles)[i])
else
tab?.customView = getSelectedTabView(resources.getStringArray(R.array.tab_titles)[i])
}
}
private fun getTabView(title: String): TextView {
val view: TextView = View.inflate(context, R.layout.layout_inactive_tab_font, null) as TextView
view.text = title
return view
}
private fun getSelectedTabView(title: String): View {
val view: TextView = View.inflate(context, R.layout.layout_active_tab_font, null) as TextView
view.text = title
return view
}
}