androidkotlinandroid-paging

I can't show my data from the API? Kotlin Android


First one it's my repo : https://github.com/Berkayszk/FiWoApp

I am getting my data using retrofit and using paging adapter. When I want to show my data using my recyclerView in my MovieFragment, I see that no data is coming. What is the reason for this error? I've been dealing with this problem for 3 days and I couldn't find a solution.

Movie Fragment = Showing my movies.

@AndroidEntryPoint
class MovieFragment : Fragment(R.layout.fragment_movie) {

private var _binding: FragmentMovieBinding? = null
private val binding get() = _binding!!
private val viewModel: MovieViewModel by viewModels()
private lateinit var movieAdapter: PopularMovieAdapter
override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    // Inflate the layout for this fragment
    _binding = FragmentMovieBinding.inflate(layoutInflater, container, false)
    return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)


    loadingData()
    setUpRv()
}


private fun loadingData() {

        movieAdapter = PopularMovieAdapter()
        lifecycleScope.launch {
            viewModel.moviesList.collect { pagingData ->
                movieAdapter.submitData(pagingData)

            }
        }
}
private fun setUpRv(){
    movieAdapter = PopularMovieAdapter()
    binding.recyclerView.apply {

        layoutManager = StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL)
        adapter = movieAdapter
        setHasFixedSize(true)
    }

}
override fun onDestroy() {
    super.onDestroy()
    _binding = null
}

}

PopularMovieAdapter = Paging Adapter

 class PopularMovieAdapter :  PagingDataAdapter<com.example.fiwoapp.model.popularmovie.Result,PopularMovieAdapter.PopularMovieHo lder>(
diffCallBack) {
class PopularMovieHolder(val binding : PopularMovieRowBinding) : ViewHolder(binding.root)

companion object {
 val diffCallBack = object : DiffUtil.ItemCallback<com.example.fiwoapp.model.popularmovie.Result>(){
    override fun areItemsTheSame(oldItem: com.example.fiwoapp.model.popularmovie.Result, newItem: com.example.fiwoapp.model.popularmovie.Result): Boolean {
        return oldItem.id==newItem.id
    }

    override fun areContentsTheSame(oldItem: com.example.fiwoapp.model.popularmovie.Result, newItem: com.example.fiwoapp.model.popularmovie.Result): Boolean {
        return oldItem == newItem
    }
}
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PopularMovieHolder {
    return PopularMovieHolder(PopularMovieRowBinding.inflate(LayoutInflater.from(parent.context),parent,false))
}

override fun onBindViewHolder(holder: PopularMovieHolder, position: Int) {
    val currentItem = getItem(position)
    holder.binding.apply {
        movieName.text = currentItem!!.title
        val imageLink = "${Constants.IMAGE_BASE_UR}+${currentItem.poster_path}"
        imageView.load(imageLink){
            crossfade(true)
            crossfade(100)

        }
    }
}

Paging Source

class PopularMovieSource(private val repository: MovieShowRepository) :PagingSource<Int,Result>(){

override suspend fun load(params: LoadParams<Int>): LoadResult<Int,Result> {
    return try {
        val currentPage = params.key ?: 1
        val response = repository.getPopularMovie(currentPage)
        val data = response.body()!!.results
        val responseData = mutableListOf<Result>()
        responseData.addAll(data)

        LoadResult.Page(
            data = responseData,
            prevKey = if (currentPage == 1) null else -1,
            nextKey = currentPage.plus(1)
        )
    } catch (e: Exception) {
        LoadResult.Error(e)
    } catch (exception: HttpException) {
        LoadResult.Error(exception)
    }

}

override fun getRefreshKey(state: PagingState<Int, com.example.fiwoapp.model.popularmovie.Result>): Int? {
    return null
}

My ViewModel

@HiltViewModel class MovieViewModel @Inject constructor(
private val repository: MovieShowRepository,
private val apiService: ApiService

) : ViewModel() {

val loading = MutableLiveData<Boolean>()

val moviesList = Pager(PagingConfig(1)) {
    PopularMovieSource(repository)
}.flow.cachedIn(viewModelScope)

//Api
val detailsMovie = MutableLiveData<DetailsResponse>()
fun loadDetailsMovie(id: Int) = viewModelScope.launch {
    loading.postValue(true)
    val response = repository.getMovieDetails(id)
    if (response.isSuccessful) {
        detailsMovie.postValue(response.body())
    }
    loading.postValue(false)
}

My Repo

  class MovieShowRepository @Inject constructor(val apiService : ApiService){
  suspend fun getPopularMovie(page : Int) = apiService.getPopularMovie()
  suspend fun getMovieDetails(id:Int) = apiService.getMovieDetails(id)

You can see all the rest of my codes in my repo. When my app runs I don't get any error but it is not showing in any yield. When I examine different repos, I see that the application works in projects with the same code lines as me, but it does not work in my project, thank you very much if you help.


Solution

  • Wrong:

    private fun loadingData() {
        movieAdapter = PopularMovieAdapter()
        lifecycleScope.launch {
            viewModel.moviesList.collect { pagingData ->
                movieAdapter.submitData(pagingData)
            }
        }
    }
    
    private fun setUpRv() {
        movieAdapter = PopularMovieAdapter() // create a new adapter?
        binding.recyclerView.apply {
            layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
            adapter = movieAdapter
            setHasFixedSize(true)
        }
    }
    

    Correct:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
    
        setUpRv() // 1st - setup RV
        loadingData() // 2nd - load data
    }
    
    
    private fun loadingData() {
        lifecycleScope.launch {
            viewModel.moviesList.collect { pagingData ->
                movieAdapter.submitData(pagingData)
            }
        }
    }
    

    In your code, the loadingData() function is called before the setUpRv() function. Therefore, when setUpRv() is called, the movieAdapter is created with default values instead of the current data from pagingData.