DEV Community

Cover image for Day 21. Pagination
Kiolk
Kiolk

Posted on

Day 21. Pagination

I really enjoy it when I can design a class that should keep logic. It feels like pure engineering. You can't do this perfectly from the first time; you have to iterate, step by step.

What I did:

I worked on the implementation of the pagination for articles. In the Android world, Google provides the Pagination Library to solve this kind of task. Every time I tried to integrate it, I had a lot of trouble. It's always a pain. So, for this project, I decided to make it simpler. 

The idea of pagination is very simple: you have a data source, and at some point, you need to load a new portion of data, called a new page. Since it's just logic, we can keep it in a pure Kotlin file. I design a simple Pagination class that holds this logic. In the constructor, it accepts a data source, a callback onNewPortionLoaded that notifies when a new portion is loaded, and a scope that to launch coroutines.  The implantation is pretty simple:

class Pagination<T>(
    private val source: suspend (page: Int) -> List<T>,
    private val onNewPortionLoaded: (data: List<T>) -> Unit,
    private val scope: CoroutineScope,
    startPosition: Int = -1,
) {

    private var startPage: Int = startPosition

    fun startLoading() {
        loadNewPortion()
    }

    fun loadNewPortion() {
        scope.launch(Dispatchers.IO) {
            startPage += 1

            val newPortion = source(startPage)

            launch(Dispatchers.Main) {
                onNewPortionLoaded(newPortion)
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

I made this class generic so that it can be used on other screens. Now, If you want to use it in a viewModel or ScreenModel in the context of KMM, you just create an instance of the class, reference its methods, and call startLoading() and loadNewPortion() in appropriate places.

class HomeScreenModel(
    private val getArticlesUseCase: GetArticleUseCase,
    private val stringProvider: StringProvider
) : ScreenModel {

    private val pagination: Pagination<Article> = Pagination(
        source = ::loadNext,
        onNewPortionLoaded = ::onNewPortionLoaded,
        scope = screenModelScope,
    )

    init {
        pagination.startLoading()
    }

    private suspend fun loadNext(page: Int): List<Article> {
        return getArticlesUseCase(GetArticlesParams(page = page))
    }

    private fun onNewPortionLoaded(newPortion: List<Article>) {
        _isLoading.value = false
        _articlesState.value += newPortion.map { it.mapToArticleUi(stringProvider) }
    }

    fun loadMoreArticles() {
        _isLoading.value = true
        pagination.loadNewPortion()
    }
}
Enter fullscreen mode Exit fullscreen mode

What I will do:

If you want to join the project, just leave a comment here, or write a message in LinkedIn.

What help I'm looking for:

Designer (create design of application in Figma)
Android/KMM developer
Any other help related to the project.

My timeline:

Day 1. Deep breath and dive
Day 2. Networking layer.
Day 3. Loading of articles.
Day 4. ArticleItem.
Day 5. Localization.
Day 6. Work on Sunday.
Day 7. First week.
Day 8. Enjoying coding.
Day 9. Expect/actual.
Day 10. TODOs.
Day 11. Friday evening.
Day 12. Frustration.
Day 13. Blocker
Day 14. Monday
Day 15. Reactions
Day 16. Feed
Day 17. stringWithFormat
Day 18. Comment
Day 19. 1 percent
Day 20. A bit of progress

See you tomorrow. 

Top comments (0)