Search code examples
androidkotlinandroid-jetpackandroid-paging

OnItemAtEndLoaded() called infinitely even when not at bottom of list


In my implementation of Android paging library 2.0, the OnItemAtEndLoaded() is called numerous times even when not scrolled to the bottom of the list. The call keep on going without stopping.

The Episodes received from the API call are ordered by publish date just like the EpisodeDao's getAllEpisodes() method.

Any help will be much appreciated.

class DetailsViewModel(
    private val episodeBoundaryCallback: EpisodeBoundaryCallback,
    private val episodeDao: EpisodeDao,
    private val pagedListConfig: PagedList.Config
) : ViewModel() {

    var episodes: LiveData<PagedList<Episode>>? = null

    fun getEpisodes(podcastId: String) {
        if (episodes != null
            && episodes!!.value != null
            && !episodes!!.value!!.isEmpty()
        ) {
            return
        }

        episodeBoundaryCallback.param = podcastId
        val dataSourceFactory = episodeDao.getAllEpisodes(podcastId)
        val pagedListBuilder =
            LivePagedListBuilder<Int, Episode>(dataSourceFactory, pagedListConfig)
        pagedListBuilder.setInitialLoadKey(1)
        pagedListBuilder.setBoundaryCallback(episodeBoundaryCallback)
        episodes = pagedListBuilder.build()
    }
}
class EpisodeBoundaryCallback(
    private val podcastsApi: PodcastsApi,
    private val skipToItDatabase: SkipToItDatabase
): PagedList.BoundaryCallback<Episode>() {

    private val tag = this::class.simpleName

    private val loadTypeRefresh = 0
    private val loadTypeAppend = 1

    lateinit var param: String
    var startPage: Long? = null

    val loading: MutableLiveData<Boolean> = MutableLiveData()
    val loadError: MutableLiveData<Boolean> = MutableLiveData()
    
    override fun onZeroItemsLoaded() {
        Log.d("REFRESHING","REFRESHING")
        AppExecutors.getInstance().diskIO().execute {
            requestPage(loadTypeRefresh, startPage)
        }
    }

    override fun onItemAtEndLoaded(itemAtEnd: Episode) {
        Log.d(tag,"APPEND")
        AppExecutors.getInstance().diskIO().execute {
            requestPage(loadTypeAppend, itemAtEnd.publishDate)
        }
    }

    override fun onItemAtFrontLoaded(itemAtFront: Episode) {

    }

    private fun requestPage(requestType: Int, loadKey: Long?) {
        val episodeResultCall = podcastsApi.getEpisodes(param, loadKey)

        val response = episodeResultCall.execute()
        if (response.isSuccessful) {
            Log.d(tag, "isSuccessful")
            loading.postValue(false)
            loadError.postValue(false)

            val body: PodcastDetails = response.body()!!
            onEpisodeFetchCallback(body, requestType)
        } else {
            Log.d(tag, "!isSuccessful")
            loading.postValue(false)
            loadError.postValue(true)
        }
    }

    var lastEpisode: Episode? = null
    private fun onEpisodeFetchCallback(
        podcastDetails: PodcastDetails,
        loadType: Int
    ) {

        skipToItDatabase.beginTransaction()
        try {
            if (loadType == loadTypeRefresh) {
                skipToItDatabase.episodeDao().deleteAllEpisodes()
            }

            val episodes = podcastDetails.episodes
            for (i in episodes) {
                i.podcastId = param
                lastEpisode = i
            }

            skipToItDatabase.episodeDao().insertEpisodes(episodes)
            skipToItDatabase.setTransactionSuccessful()
        } finally {
            skipToItDatabase.endTransaction()
        }
    }
}
@Dao
interface EpisodeDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertEpisodes(episodes: List<Episode>)

    @Query("SELECT * FROM episodes WHERE podcast_id = :podcastId ORDER BY publish_date DESC")
    fun getAllEpisodes(podcastId: String):  DataSource.Factory<Int, Episode>

    @Query("DELETE FROM episodes")
    fun deleteAllEpisodes()
}
    @Headers("X-ListenAPI-Key: ${BuildConfig.apiKey}")
    @GET("podcasts/{podcast_id}?sort=recent_first")
    fun getEpisodes(
        @Path("podcast_id") podcastId: String,
        @Query("next_episode_pub_date") nextEpisodePubDate: Long?
    ): Call<PodcastDetails>
return new PagedList.Config.Builder()
                .setPageSize(10)
                .setPrefetchDistance(5)
                .setEnablePlaceholders(true)
                .setInitialLoadSizeHint(30)
                .setMaxSize(60)
                .build();

Solution

  • Apparently this was an issue with my recycler view size in XML