I'm having an issue using Paging 3 library. I'm using retrofit to get data and paging 3 to display it but what is happening right now is that when I open my fragment for the first time, nothing is displayed on the fragment but when I close this fragment and open it again, data is displayed. What is happening?
I navigate from one fragment to another using Navigation. I'm using Koin in this project for dependencies.
Instead of navigate to fragment and then load data, what its doing right now is loading data with Paging 3 and then, it navigates to Fragment and display the data(this only happen after open this fragment one time and close it)
How can I fix this? I don't know why the first time dont show data and then I don't know why it loads data before navigating instead of loadind data after navigating using the library.
My code:
Service:
interface APICalls{
@GET(MYAPIURL)
suspend fun getData(
@Header("Auth") auth : String,
@Query("pageSize") pageSize:Int
):Response<ResponseData>
}
Models:
data class ResponseData(
@SerializedName("listData") val listData:MutableList<DataAPI>,
@SerializedName("pageSize") val pageSize : Int
):Serializable
data class DataAPI(
@SerializedName("id") val id:Int,
@SerializedName("data")val data: String
): Serializable
Result wrapper:
class Result<out T:Any>{
data class Success<T:Any>(val value: T): Result<T>()
data class Failure(val message:String, val errorCode:Int?):Result<Nothing>()
}
PagingSource:
val responseData = mutableListOf<DataAPI>()
class DataAPIPagingSource(private val token:String,private val apiCalls:APICalls) : PagingSource<Int,DataAPI>{
override fun getRefreshKey(...):Int?{
return null
}
override suspend fun load(params : LoadParams<Int>):LoadResult<Int,DataAPI>{
return try{
val currentPage = params.key ?: 1
val response = apiCalls.getData(token)
response.body()?.let{
Result.Success(it)
}?: run{
Result.Failure(response.message(),response.code())
}
val data = response.body()?.listData ?: emptyList()
responseData.addAll(data)
LoadResult.Page(responseData,if(currentPage ==1) null else -1),currentPage.plus(1)
}catch(e:Exception){
LoadResult.Error(e)
}
}
}
ViewModel:
class DataViewModel(private val apiCalls:APICalls): ViewModel {
//I get this token in shared preference
val token = .....
val mydata = getDataList()
.map{pagingData -> pagingData.map{DataModel.DataItem(it)}}
private fun getDataList(){
return Pager(PagingConfig(25)){
DataAPIPagingSource(token,apiCalls)
}.flow.cachedIn(viewModelScope)
}
}
sealed class DataModel{
data class DataItem(val dataitem: DataAPI) : DataModel()
}
private val DataModel.DataItem.identificator : Int
get() = this.dataItem.id
Fragment:
class MyFragment : Fragment(){
private val myAdapter : DataAdapter by lazy{
DataAdapter()
}
private val viewModelFactory : ViewModelFactory by inject()
private val dataViewModel : DataViewModel by navGraphViewModels(R.id.nav_graph){viewModelFactory}
override fun onViewCreated(...){
super.onViewCreated(...)
binding.myRecyclerView.apply{
adapter = myAdapter
layoutManager = StaggeredGridLayoutManager(1,StaggeredGridLayoutManager.VERTICAL)
setHasFixedSize(true)
}
lyfecycleScope.launch{
dataViewModel.mydata.collect{myAdapter.submitData(it)}
}
}
}
Adapter:
class DataAdapter : PagingDataAdapter<DataModel,RecyclerView.ViewHolder>(DataModelComparator){
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position:Int){
val dataModel : DataModel? = getItem(position)
dataModel.let{
when(dataModel){
is DataModel.DataItem ->{
val viewHolder = holder as DataItemViewHolder
viewHolder.binding.textview1.text = dataModel.dataitem.data
}
}
}
}
override fun getItemViewType(position:Int):Int{
return when(getItem(position)){
is DataModel.DataItem -> R.layout.item_data
null -> throw UnsupportedOperationException("Unknown view")
}
}
override fun onCreateViewHolder(...){
return when(viewType){
R.layout.item_data ->{
DataItemViewHolder(ItemDataBinding.inflate(...))
}
}
}
class DataItemViewHolder(val binding: DataItemBinding): RecyclerView.ViewHolder(binding.root)
companion object {
val DataModelComparator = object : DiffUtil.ItemCallback<DataModel>() {
override fun areItemsTheSame(oldItem: Movie, newItem: Movie): Boolean {
return oldItem.dataitem.id == newItem.dataitem.id
}
override fun areContentsTheSame(oldItem: DataModel, newItem: DataModel): Boolean {
return oldItem == newItem
}
}
}
}