kizitonwose / Calendar

A highly customizable calendar view and compose library for Android and Kotlin Multiplatform.
MIT License
4.77k stars 509 forks source link

failure loading custom class java.lang.NoSuchMethodException: com.ahmetkaan.kediy.Calendar.<init> [class android.content.Context] #468

Closed Kaanavciexe closed 1 year ago

Kaanavciexe commented 1 year ago

Version: [e.g. 2.3.0]

I am using this library with my custom room event database. Here is my Calendars Xml;

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintTop_toTopOf="parent">

        <com.kizitonwose.calendar.view.CalendarView
            android:id="@+id/calendarView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/transparent"
            android:clickable="true"
            android:focusable="true"
            app:cv_dayViewResource="@layout/calendar_day_layout"
            app:cv_monthHeaderResource="@layout/calendar_header"
            app:cv_monthViewClass="com.ahmetkaan.kediy.Calendar"/>

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/exThreeRv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:nestedScrollingEnabled="false"
            android:layout_marginTop="10dp"/>

    </LinearLayout>

I am showing the events in this recyclerView. And here is my code;

package com.ahmetkaan.kediy

import android.annotation.SuppressLint
import android.graphics.Color
import android.os.Bundle
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.view.children
import androidx.core.view.isVisible
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.ahmetkaan.kediy.Adapter.EventsAdapter
import com.ahmetkaan.kediy.databinding.CalendarDayLayoutBinding
import com.ahmetkaan.kediy.databinding.CalendarHeaderBinding
import com.ahmetkaan.kediy.databinding.FragmentCalendarBinding
import com.ahmetkaan.kediy.eventsData.Events
import com.ahmetkaan.kediy.eventsData.EventsDatabase
import com.kizitonwose.calendar.core.CalendarDay
import com.kizitonwose.calendar.core.CalendarMonth
import com.kizitonwose.calendar.core.DayPosition
import com.kizitonwose.calendar.view.MonthDayBinder
import com.kizitonwose.calendar.view.MonthHeaderFooterBinder
import com.kizitonwose.calendar.view.ViewContainer
import kotlinx.coroutines.launch
import java.time.DayOfWeek
import java.time.LocalDate
import java.time.YearMonth
import java.time.format.DateTimeFormatter
import java.util.Locale

class Calendar : BaseFragment() {
    private val today = LocalDate.now()
    private lateinit var binding: FragmentCalendarBinding
    private var selectedDate: LocalDate? = null
    var arrEvents = ArrayList<Events>()
    var arrLocale = ArrayList<LocalDate>()
    var eventsAdapterK: EventsAdapter = EventsAdapter()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding = FragmentCalendarBinding.bind(view)

        binding.exThreeRv.setHasFixedSize(true)
        binding.exThreeRv.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)

        eventsAdapterK.setOnClickListenerK(onClickedK)

        if (savedInstanceState == null) {
            // Show today's events initially.
            binding.calendarView.post {selectDate(today)}
        }

        launch {
            context?.let {
                val events = EventsDatabase.getDatabase(it).eventDao().getDateEvents(getFindDate(today))
                eventsAdapterK.setData(events)
                arrEvents = events as ArrayList<Events>
                binding.exThreeRv.adapter = eventsAdapterK
                for (i in arrEvents) {
                    i.findDate?.let { it1 -> arrLocale.add(it1) }
                }
            }
        }

        binding.createEvent.setOnClickListener{
            val bundle = Bundle()
            val format = DateTimeFormatter.ofPattern("dd MMMM yyyy", Locale("tr", "TR"))
            if (selectedDate == null) {
                bundle.putString("date",null)
            } else {
                bundle.putString("date", selectedDate!!.format(format))
            }
            findNavController().navigate(R.id.action_calendar_to_createEvent2, bundle)
        }
    }

    private fun getFindDate(dateSelection : LocalDate) : String {
        val currentDate = dateSelection.toString()
        val theCurrentMonthInt = currentDate.split("-")[1].toInt()
        val theCurrentYear = currentDate.split("-")[0]
        val theCurrentMonth = when (theCurrentMonthInt) {
            1 -> "Ocak"
            2 -> "Şubat"
            3 -> "Mart"
            4 -> "Nisan"
            5 -> "Mayıs"
            6 -> "Haziran"
            7 -> "Temmuz"
            8 -> "Ağustos"
            9 -> "Eylül"
            10 -> "Ekim"
            11 -> "Kasım"
            12 -> "Aralık"
            else -> ""
        }
        val theCurrentDay = currentDate.split("-")[2]

        return "$theCurrentDay $theCurrentMonth $theCurrentYear"
    }

    private val onClickedK = object : EventsAdapter.OnItemClickListenerK {
        override fun onClickedK(eventId: Int) {
            val bundle = Bundle()
            bundle.putInt("eventId", eventId)
            val bottomSheetDialog = ShowEvent()
            bottomSheetDialog.arguments = bundle
            bottomSheetDialog.show(parentFragmentManager, "eventsShowTag")
        }
    }

    private fun selectDate(date: LocalDate) {
        if (selectedDate != date) {
            val oldDate = selectedDate
            selectedDate = date
            oldDate?.let { binding.calendarView.notifyDateChanged(it) }
            binding.calendarView.notifyDateChanged(date)
            updateAdapterForDate(date)
        }
    }

    private fun deleteEvent(eventId: Int) {
        launch {
            context?.let {
                EventsDatabase.getDatabase(it).eventDao().deleteSpecificEvent(eventId)
            }
        }
    }

    private fun updateAdapterForDate(date: LocalDate) {

    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentCalendarBinding.inflate(layoutInflater, container, false)

        val currentMonth = YearMonth.now()
        val startMonth = currentMonth.minusMonths(100)
        val endMonth = currentMonth.plusMonths(100)
        val daysOfWeek = DayOfWeek.values()
        binding.calendarView.setup(startMonth, endMonth, daysOfWeek[0])
        binding.calendarView.scrollToMonth(currentMonth)

        @SuppressLint("RestrictedApi")
        class DayViewContainer(view: View) : ViewContainer(view) {
            val textView = CalendarDayLayoutBinding.bind(view).calendarDayText
            val dotView = CalendarDayLayoutBinding.bind(view).exThreeDotView

            lateinit var day: CalendarDay

            init {
                view.setOnClickListener {
                    if (day.position == DayPosition.MonthDate) {
                        val currentSelection = selectedDate
                        if (currentSelection == day.date) {
                            selectedDate = null
                            binding.calendarView.notifyDateChanged(currentSelection)
                        } else {
                            selectedDate = day.date
                            binding.calendarView.notifyDateChanged(day.date)
                            if (currentSelection != null) {
                                binding.calendarView.notifyDateChanged(currentSelection)
                            }
                        }
                    }
                }
            }
        }

            binding.calendarView.dayBinder = object : MonthDayBinder<DayViewContainer> {
                override fun create(view: View) = DayViewContainer(view)

                override fun bind(container: DayViewContainer, data: CalendarDay) {
                    val textView = container.textView
                    container.day = data
                    val day = data
                    textView.text = day.date.dayOfMonth.toString()
                    val dotView = container.dotView

                    if (selectedDate != null) {
                        launch {
                            context?.let {
                                val events = EventsDatabase.getDatabase(it).eventDao().getDateEvents(getFindDate(selectedDate!!))
                                eventsAdapterK.setData(events)
                                arrEvents = events as ArrayList<Events>
                                binding.exThreeRv.adapter = eventsAdapterK
                            }
                        }
                    } else {
                        launch {
                            context?.let {
                                val events = EventsDatabase.getDatabase(it).eventDao().getDateEvents(" ")
                                eventsAdapterK.setData(events)
                                arrEvents = events as ArrayList<Events>
                                binding.exThreeRv.adapter = eventsAdapterK
                            }
                        }
                    }

                    if (day.position == DayPosition.MonthDate) {
                        textView.visibility = View.VISIBLE
                        dotView.isVisible = arrLocale.contains(day.date)
                        if (day.date == selectedDate) {
                            textView.setTextColor(Color.WHITE)
                            textView.setBackgroundResource(R.drawable.selection_background)
                            println(arrLocale.contains(day.date))
                            dotView.isVisible = arrLocale.contains(day.date)
                        } else {
                            textView.setTextColor(ContextCompat.getColor(requireContext(), R.color.noteTitleColor))
                            textView.background = null
                        }
                    } else {
                        textView.visibility = View.INVISIBLE
                        dotView.visibility = View.INVISIBLE
                    }
                }
            }
            class MonthViewContainer(view: View) : ViewContainer(view) {
                val binding = CalendarHeaderBinding.bind(view)
                val textView = binding.exSixMonthText
                val legendLayout = binding.legendLayout.root
            }
            binding.calendarView.monthHeaderBinder =
                object : MonthHeaderFooterBinder<MonthViewContainer> {
                    override fun create(view: View) = MonthViewContainer(view)
                    override fun bind(container: MonthViewContainer, data: CalendarMonth) {
                        val currentDate = data.yearMonth.toString()
                        val theCurrentMonthInt = currentDate.split("-")[1].toInt()
                        val theCurrentYear = currentDate.split("-")[0]
                        val theCurrentMonth = when (theCurrentMonthInt) {
                            1 -> "Ocak"
                            2 -> "Şubat"
                            3 -> "Mart"
                            4 -> "Nisan"
                            5 -> "Mayıs"
                            6 -> "Haziran"
                            7 -> "Temmuz"
                            8 -> "Ağustos"
                            9 -> "Eylül"
                            10 -> "Ekim"
                            11 -> "Kasım"
                            12 -> "Aralık"
                            else -> ""
                        }
                        container.textView.text = "$theCurrentMonth $theCurrentYear"
                        if (container.legendLayout.tag == null) {
                            container.legendLayout.tag = data.yearMonth
                            container.legendLayout.children.map { it as TextView }
                                .forEachIndexed { index, tv ->
                                    val trDaysOfWeek = arrayListOf("Pzt", "Sal", "Çar", "Per", "Cum", "Cmt", "Paz")
                                    tv.text = trDaysOfWeek[index]
                                    tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14F)
                                    tv.setTextColor(ContextCompat.getColor(requireContext(), R.color.noteTitleColor))
                                }
                        }
                    }
                }

        return binding.root
    }

}

But when i open this fragment or when i create an event and come back, i am getting this error;

failure loading custom class
                                                                                                    java.lang.NoSuchMethodException: com.ahmetkaan.kediy.Calendar.<init> [class android.content.Context]
                                                                                                        at java.lang.Class.getConstructor0(Class.java:2363)
                                                                                                        at java.lang.Class.getDeclaredConstructor(Class.java:2201)
                                                                                                        at com.kizitonwose.calendar.view.internal.UtilsKt.setupItemRoot(Utils.kt:84)
                                                                                                        at com.kizitonwose.calendar.view.internal.monthcalendar.MonthCalendarAdapter.onCreateViewHolder(MonthCalendarAdapter.kt:61)
                                                                                                        at com.kizitonwose.calendar.view.internal.monthcalendar.MonthCalendarAdapter.onCreateViewHolder(MonthCalendarAdapter.kt:30)
                                                                                                        at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:7719)
                                                                                                        at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6804)
                                                                                                        at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6688)
                                                                                                        at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6684)
                                                                                                        at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2362)
                                                                                                        at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1662)
                                                                                                        at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1622)
                                                                                                        at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:687)
                                                                                                        at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4604)
                                                                                                        at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:3981)
                                                                                                        at android.view.View.measure(View.java:26357)
                                                                                                        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
                                                                                                        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1608)
                                                                                                        at android.widget.LinearLayout.measureVertical(LinearLayout.java:878)
                                                                                                        at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
                                                                                                        at android.view.View.measure(View.java:26357)
                                                                                                        at androidx.constraintlayout.widget.ConstraintLayout$Measurer.measure(ConstraintLayout.java:811)
                                                                                                        at androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.measure(BasicMeasure.java:466)
                                                                                                        at androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.measureChildren(BasicMeasure.java:134)
                                                                                                        at androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.solverMeasure(BasicMeasure.java:278)
                                                                                                        at androidx.constraintlayout.core.widgets.ConstraintWidgetContainer.measure(ConstraintWidgetContainer.java:120)
                                                                                                        at androidx.constraintlayout.widget.ConstraintLayout.resolveSystem(ConstraintLayout.java:1594)
                                                                                                        at androidx.constraintlayout.widget.ConstraintLayout.onMeasure(ConstraintLayout.java:1708)
                                                                                                        at android.view.View.measure(View.java:26357)
                                                                                                        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
                                                                                                        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
                                                                                                        at android.view.View.measure(View.java:26357)
                                                                                                        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
                                                                                                        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
                                                                                                        at android.view.View.measure(View.java:26357)
                                                                                                        at androidx.constraintlayout.widget.ConstraintLayout$Measurer.measure(ConstraintLayout.java:811)
                                                                                                        at androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.measure(BasicMeasure.java:466)
                                                                                                        at androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.measureChildren(BasicMeasure.java:134)
                                                                                                        at androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.solverMeasure(BasicMeasure.java:278)
                                                                                                        at androidx.constraintlayout.core.widgets.ConstraintWidgetContainer.measure(ConstraintWidgetContainer.java:120)
                                                                                                        at androidx.constraintlayout.widget.ConstraintLayout.resolveSystem(ConstraintLayout.java:1594)
                                                                                                        at androidx.constraintlayout.widget.ConstraintLayout.onMeasure(ConstraintLayout.java:1708)
                                                                                                        at android.view.View.measure(View.java:26357)
                                                                                                        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
                                                                                                        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
                                                                                                        at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:145)
2023-05-15 12:30:10.680 11854-11854 CalendarView            com.ahmetkaan.kediy                  E      at android.view.View.measure(View.java:26357)
                                                                                                        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
                                                                                                        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1608)
                                                                                                        at android.widget.LinearLayout.measureVertical(LinearLayout.java:878)
                                                                                                        at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
                                                                                                        at android.view.View.measure(View.java:26357)
                                                                                                        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
                                                                                                        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
                                                                                                        at android.view.View.measure(View.java:26357)
                                                                                                        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
                                                                                                        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1608)
                                                                                                        at android.widget.LinearLayout.measureVertical(LinearLayout.java:878)
                                                                                                        at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
                                                                                                        at android.view.View.measure(View.java:26357)
                                                                                                        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
                                                                                                        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
                                                                                                        at com.android.internal.policy.DecorView.onMeasure(DecorView.java:760)
                                                                                                        at android.view.View.measure(View.java:26357)
                                                                                                        at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:3926)
                                                                                                        at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:2612)
                                                                                                        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2884)
                                                                                                        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2328)
                                                                                                        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9087)
                                                                                                        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1231)
                                                                                                        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1239)
                                                                                                        at android.view.Choreographer.doCallbacks(Choreographer.java:899)
                                                                                                        at android.view.Choreographer.doFrame(Choreographer.java:832)
                                                                                                        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1214)
                                                                                                        at android.os.Handler.handleCallback(Handler.java:942)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:99)
                                                                                                        at android.os.Looper.loopOnce(Looper.java:201)
                                                                                                        at android.os.Looper.loop(Looper.java:288)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:7872)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)

I tried to fix it. Actually before this time, sometimes it works well. It didnt throwing any error message when i create an event and come to the fragment. But rarely i couldnt create an event (or i could but couldnt show it) and now, I am getting this error everytime. How can i fix this? If you want i can show my other codes too.

pushpulldecoder commented 1 year ago

Can you share your compose version. It seems like WeekCalendar is also broken in 1.5.0-alpha04 but works fine with earlier versions

kizitonwose commented 1 year ago

@Kaanavciexe This is because the app:cv_monthViewClass="com.ahmetkaan.kediy.Calendar" provided in xml cannot be instantiated as the constructor is not found.

See instructions for obfuscation.