It's been 2 days I'm trying to learn how to use the new Paging Library with the Kotlin Language (first time too)
So I've read many guide / tutorial and Github repo (https://github.com/STAR-ZERO/paging-retrofit-sample) for implementing this paging library and basically my trouble is my LiveData<PagedList<Discover>>
inside my ViewModel
is trigger before my api call is ending and I don't know why and I feel the call callback.onResult(it?.results.orEmpty(), null, 2)
doesn't do anything
I'm using this version android.arch.paging:runtime:1.0.1
You can find the repo of my project here : https://github.com/florian-do/TMDB
logcat :
D/DataSourceFactory: : create()
D/SequentialDataSource: loadInitial:
D/Interceptor: https://api.themoviedb.org/3/discover/movie?api_key=??
D/MainFragment: : observe 0
D/SequentialDataSource: response code -> 200
D/SequentialDataSource: list size: 20
Here there is my code :
Fragment.kt
val adapter = DiscoverAdapter(context!!, diffCallBack)
binding.rvFeed.layoutManager = GridLayoutManager(context, 3)
binding.rvFeed.setHasFixedSize(true)
binding.rvFeed.adapter = adapter
viewModel.data.observe(this, Observer {
Log.d(TAG, ": observe "+it?.size)
})
MainViewModel.kt
class MainViewModel : ViewModel() {
var amount = ObservableField<String>()
val data : LiveData<PagedList<Discover>>
init {
val config = PagedList.Config.Builder()
.setPageSize(20)
.setEnablePlaceholders(false)
.build()
val api : DiscoverService = App.retrofit.create(DiscoverService::class.java)
val dataSourceFactory = DataSourceFactory(api)
data = LivePagedListBuilder(dataSourceFactory, config).build()
}
}
DataSourceFactory.kt
class DataSourceFactory(api: DiscoverService) : DataSource.Factory<Int, Discover>() {
val source = SequentialDataSource(api)
override fun create(): DataSource<Int, Discover> {
return source
}
}
SequentialDataSource.kt
class SequentialDataSource(val api : DiscoverService) : PageKeyedDataSource<Int, Discover>() {
private val TAG = "SequentialDataSource"
override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, Discover>) {
Log.d(TAG, "loadInitial: ")
api.getDiscover(TMDBClient.API_KEY).enqueue(object : Callback<DiscoverReponse> {
override fun onFailure(call: Call<DiscoverReponse>, t: Throwable) {
Log.d(TAG, ": FAIL")
}
override fun onResponse(call: Call<DiscoverReponse>, response: Response<DiscoverReponse>) {
Log.d(TAG, ": response code -> "+response.code())
val it = response.body();
Log.d(TAG, "list size: "+it?.results?.size)
response.body()?.let {
callback.onResult(it.results, null, 2)
}
}
})
}
override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, Discover>) {
Log.d(TAG, "loadAfter: "+params.key)
}
override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, Discover>) {
Log.d(TAG, "loadBefore: "+params.key)
}
}
Well, after many changed i've found something who fix the problem but it's so weird.
If I use enqueue
with Retrofit 2.3 it will doesn't work but if i do a .execute()
the LiveData is correctly triggered
If someone have a better explanation of this problem your very welcome !
Edit :
I've just read the Paging library overview
page on android website and i found this :
To display data from a backend server, use the synchronous version of the Retrofit API to load information into your own custom DataSource object.
loadInitial()
, loadAfter()
, loadBefore()
are already asynchronous. If you try to println(Thread.currentThread().name)
you will get arch_disk_io_0
. To solve this you need to execute code like it's synchronous in order to not miss the callback. You will miss the callback if you switch threads, library is already doing it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With