Home > Back-end >  How to use Adapter for RecyclerView in Android
How to use Adapter for RecyclerView in Android

Time:01-18

In my application I want create custom calendar with RecyclerView.
I write below codes but when show days into recyclerview adapter show me force close error!
My Adapter codes:

class DaysAdapter constructor(val context: Context, private val items: MutableList<DayEntity>) :
    RecyclerView.Adapter<DaysAdapter.ViewHolder>() {

    private val TYPE_HEADER = 0
    private val TYPE_DAY = 1
    private var firstDayDayOfWeek = 0
    private var totalDays = 0

    init {
        firstDayDayOfWeek = items[0].dayOfWeek
        totalDays = items.size
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        return ViewHolder(inflater.inflate(R.layout.item_day_new, parent, false))
    }

    override fun getItemCount() = 7 * 7

    override fun getItemViewType(position: Int): Int {
        return if (isPositionHeader(position)) {
            TYPE_HEADER
        } else {
            TYPE_DAY
        }
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        //New position
        var newPosition = position
        newPosition  = 6 - (newPosition % 7) * 2
        if (totalDays < position - 6 - firstDayDayOfWeek) {
            return
        }
        //Day
        if (!isPositionHeader(newPosition)) {
            if (newPosition - 7 - firstDayDayOfWeek >= 0) {
                holder.dayTxt.text = items[newPosition - 7 - items[0].dayOfWeek].num
                //Holiday
                if (items[newPosition - 7 - firstDayDayOfWeek].isHoliday) {
                    holder.dayTxt.setTextColor(ContextCompat.getColor(context, R.color.red))
                } else {
                    holder.dayTxt.setTextColor(ContextCompat.getColor(context, R.color.black))
                }
            }
        } else {
            //Header
            holder.dayTxt.text = Constants.FIRST_CHAR_OF_DAYS_OF_WEEK_NAME[newPosition]
        }
    }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val dayTxt = itemView.findViewById(R.id.dayTxt) as TextView

        @SuppressLint("SetTextI18n")
        fun bind() {

        }
    }

    private fun isPositionHeader(position: Int) = position < 7
}

Error Message in Logcat:

java.lang.IndexOutOfBoundsException: Index: 34, Size: 30
        at java.util.ArrayList.get(ArrayList.java:437)
        at myapp.mycharts.calendar_my.utils.pages.month.DaysAdapter.onBindViewHolder(DaysAdapter.kt:53)
        at myapp.mycharts.calendar_my.utils.pages.month.DaysAdapter.onBindViewHolder(DaysAdapter.kt:15)
        at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:7254)
        at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7337)
        at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6194)
        at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6460)
        at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6300)
        at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6296)
        at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2330)
        at androidx.recyclerview.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:572)
        at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1591)
        at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:668)
        at androidx.recyclerview.widget.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:170)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4309)
        at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:3686)
        at android.view.View.measure(View.java:23169)

Show error for this line:

holder.dayTxt.text = items[newPosition - 7 - items[0].dayOfWeek].num

My Fragment codes for fill days entity:

class CalendarMonthFragment : Fragment() {

    private lateinit var binding: FragmentCalendarMonthBinding

    private val utils by lazy { UtilsKotlin.getInstance(requireContext()) }
    private var monthOffset = 0
    private lateinit var persianDate: PersianDate

    private val daysAdapter by lazy { DaysAdapter(requireContext(), daysList) }
    private val daysList = mutableListOf<DayEntity>()

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        binding = FragmentCalendarMonthBinding.inflate(layoutInflater)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        //Utils
        utils.let { utils ->
            //Persian date
            persianDate = utils.today
            //Init days
            arguments?.let {
                monthOffset = it.getInt(Constants.OFFSET_ARGUMENT)
                daysList.addAll(utils.getDays(monthOffset).toMutableList())
            }
        }
        //Days recyclerview
        daysAdapter.notifyDataSetChanged()
        //InitViews
        binding.apply {
            //Recyclerview
            daysRecyclerview.apply {
                layoutManager = GridLayoutManager(requireContext(), 7)
                adapter = daysAdapter
            }
        }
    }
}

How can I fix it and show data into recyclerview ?

CodePudding user response:

You need to add a check for preventing crash for this line holder.dayTxt.text = items[newPosition - 7 - items[0].dayOfWeek].num

val position = newPosition - 7 - items[0].dayOfWeek

if(position != -1 && position < items.size) {
    holder.dayText.text = items[position].num
}

try above code...

CodePudding user response:

IndexOutOfBounds says, that in items there's no element with such position number. At first check if "items" consists any elements, if yes then check if items[0] exists. if yes then you can get result number from val resultPos = newPosition - 7 - items[0].dayOfWeek and the check if items.size > resultPos if yes then you can get this element. I hope it can help you.

  • Related