Tuesday, 22 March 2022

Unexpected behaviour on indexing in paging library 3

Hey I am working in Viewpager 2 with Paging library 3. I used viewpager 2 to show single date in page and doing increment/decrement by page swiping. I am passing current date in my current item of viewpager. I did this successfully without any problem. But sometimes when I open it adding extra page with wrong index number as my current item in viewpager. I am adding my youtube link. In video, I am clicking on button and opening next activity. Inside that I am implemented the viewpager + paging library. I am passing current date as [19/03/2022]. Sometimes it open correct page but sometimes my paging or viewpager loading [14/03/2022], extra page and open in wrong index number. You can see clearly in my video what I mean that.

Log in video

1st Time click

2022-03-19 15:07:38.094 7502-7502/com.example.viewpagerexample E/Page number: 0 ::-> [19/03/2022]
2022-03-19 15:07:38.232 7502-7502/com.example.viewpagerexample E/Page number: -1 ::-> [14/03/2022, 15/03/2022, 16/03/2022, 17/03/2022, 18/03/2022]

2nd Time Click

2022-03-19 15:07:40.226 7502-7502/com.example.viewpagerexample E/Page number: 0 ::-> [19/03/2022]
2022-03-19 15:07:40.255 7502-7502/com.example.viewpagerexample E/Page number: -1 ::-> [14/03/2022, 15/03/2022, 16/03/2022, 17/03/2022, 18/03/2022]

3rd Time Click

2022-03-19 15:07:42.692 7502-7502/com.example.viewpagerexample E/Page number: 0 ::-> [19/03/2022]
2022-03-19 15:07:42.731 7502-7502/com.example.viewpagerexample E/Page number: -1 ::-> [14/03/2022, 15/03/2022, 16/03/2022, 17/03/2022, 18/03/2022]

4th Time Click

2022-03-19 15:07:44.282 7502-7502/com.example.viewpagerexample E/Page number: 0 ::-> [19/03/2022]
2022-03-19 15:07:44.307 7502-7502/com.example.viewpagerexample E/Page number: -1 ::-> [14/03/2022, 15/03/2022, 16/03/2022, 17/03/2022, 18/03/2022]

5th Time Click

2022-03-19 15:07:46.713 7502-7502/com.example.viewpagerexample E/Page number: 0 ::-> [19/03/2022]
2022-03-19 15:07:46.738 7502-7502/com.example.viewpagerexample E/Page number: -1 ::-> [14/03/2022, 15/03/2022, 16/03/2022, 17/03/2022, 18/03/2022]

6th Time click you can see it added extra page with wrong index in my viewpager.

2022-03-19 15:07:48.962 7502-7502/com.example.viewpagerexample E/Page number: 0 ::-> [19/03/2022]
2022-03-19 15:07:48.984 7502-7502/com.example.viewpagerexample E/Page number: -1 ::-> [14/03/2022, 15/03/2022, 16/03/2022, 17/03/2022, 18/03/2022]
2022-03-19 15:07:48.998 7502-7502/com.example.viewpagerexample E/Page number: -2 ::-> [09/03/2022, 10/03/2022, 11/03/2022, 12/03/2022, 13/03/2022]

You Can see same log in my youtube video.

enter image description here

MainActivity.kt

import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_IDLE
import com.example.viewpagerexample.databinding.ActivityMainBinding
import kotlinx.coroutines.flow.collectLatest

class MainActivity : AppCompatActivity() {

    private val viewModel by viewModels<ViewPagerViewModel>()
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val adapter = ViewPagerAdapter()
        lifecycleScope.launchWhenCreated {
            viewModel.dataList.collectLatest {
                adapter.submitData(it)
            }
        }
        binding.viewpager.adapter = adapter

        binding.next.setOnClickListener {
            if (binding.viewpager.scrollState == SCROLL_STATE_IDLE) {
                binding.viewpager.setCurrentItem(binding.viewpager.currentItem.plus(1), true)
            }
        }

        binding.previous.setOnClickListener {
            if (binding.viewpager.scrollState == SCROLL_STATE_IDLE) {
                binding.viewpager.setCurrentItem(binding.viewpager.currentItem.minus(1), true)
            }
        }
    }
}

ViewPagerPagingSource.kt

import android.util.Log
import androidx.paging.PagingSource
import androidx.paging.PagingState
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*

class ViewPagerPagingSource(
    private val dataSource: DataSource
) : PagingSource<Int, Date>() {

    private val format = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault())

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Date> {
        val position = params.key ?: 0

        return try {
            val data = dataSource.returnData(position)
            Log.e("Page number", "$position ::-> ${data.result.map(format::format)}")
            LoadResult.Page(
                data = data.result,
                prevKey = data.prevKey,
                nextKey = data.nextKey
            )
        } catch (exception: IOException) {
            LoadResult.Error(exception)
        }
    }

    override fun getRefreshKey(state: PagingState<Int, Date>): Int? {
        return state.anchorPosition?.let { anchorPosition ->
            val anchorPage = state.closestPageToPosition(anchorPosition)
            anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)
        }
    }
}

ViewPagerViewModel.kt

import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.paging.Pager
import androidx.paging.PagingConfig
import java.util.*

class ViewPagerViewModel(app: Application) : AndroidViewModel(app) {

    // pass current date as limit date
    private val currentDateLimitDataSource = DataSource(size = 5, limitDate(), limitDate())

    val dataList =
        Pager(config = PagingConfig(
            pageSize = 1
        ), pagingSourceFactory = {
            ViewPagerPagingSource(currentDateLimitDataSource)
        }).flow

    private fun currentDate(): Date {
        val calendar = Calendar.getInstance()
        calendar.add(Calendar.DATE, -10)
        return calendar.time
    }

    private fun limitDate(): Date {
        val calendar = Calendar.getInstance()
        return calendar.time
    }
}

DataSource.kt

import java.util.*

class DataSource(
    private val size: Int = 5,
    private val currentDate: Date,
    private val limitDate: Date? = null
) {

    fun returnData(pageNumber: Int): Result {
        val dateList = mutableListOf<Date>()

        val startDateForPage = startDate(pageNumber)
        val tempCalendar = Calendar.getInstance()

        tempCalendar.time = startDateForPage
        val lastDateForPage = endDate(startDateForPage)

        var index = size
        while (tempCalendar.time <= lastDateForPage && index-- > 0) {
            dateList.add(tempCalendar.time)
            tempCalendar.add(Calendar.DATE, 1)
        }
        return Result(
            result = dateList,
            pageNumber - 1,
            if (lastDateForPage == limitDate)
                null
            else
                pageNumber + 1
        )
    }

    private fun startDate(pageNumber: Int): Date {
        Calendar.getInstance().let {
            it.time = currentDate
            it.add(Calendar.DATE, pageNumber * size)
            return it.time
        }
    }

    private fun endDate(firstDateForPage: Date): Date? {
        Calendar.getInstance().let {
            it.time = firstDateForPage
            it.add(Calendar.DATE, size)

            limitDate?.let { limit ->
                return if (it.time > limit) limit else it.time
            } ?: run {
                return it.time
            }
        }
    }

    data class Result(
        val result: MutableList<Date>,
        val prevKey: Int?,
        val nextKey: Int?
    )
}

My whole source code Github

build.gradle.kt

dependencies {

    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'

    implementation "androidx.viewpager2:viewpager2:1.0.0"

    implementation "androidx.paging:paging-runtime-ktx:3.1.1"

    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1"
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.1"
    implementation "android.arch.lifecycle:extensions:1.1.1"
    implementation 'androidx.fragment:fragment-ktx:1.4.1'

    //noinspection GradleDynamicVersion
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}


from Unexpected behaviour on indexing in paging library 3

No comments:

Post a Comment