highcharts / highcharts-android

Android wrapper for Highcharts usage
Other
125 stars 30 forks source link

Android : Highcharts loads wrong data in the recycler view when scrolled. #230

Closed Nagesh-Robosoft closed 2 months ago

Nagesh-Robosoft commented 2 years ago

Expected behaviour

For the given set of the chart data, high chart view in the recycler view should load respective position data.

Actual behaviour

High chart view loaded different charts when the item in the recycler view is reused(recycled).

Live demo with steps to reproduce

Product version

'com.github.highcharts:highcharts-android:9.3.2'

Affected browser(s)

All android devices.

Note: Found the solution as chartView.reload(), but this is deprecated and also implementing this will give the delay in loading the highchart graph. Also tried with the following solution mentioned in the high chart forum. override fun getItemId(position: Int): Long { return position.hashCode().toLong() }

    adapter?.setHasStableIds(true)

Still we find the same issue.

cc: @soommy12

soommy12 commented 2 years ago

HI @Nagesh-Robosoft ! Thank you for your question and detailed description of the problem. I will investigate and back with the answer.

Nagesh-Robosoft commented 2 years ago

@soommy12 Thank you for the quick response. It would be helpful if I know about the progress on this issue. Your time and effort is appreciated! Thank you.

soommy12 commented 2 years ago

@Nagesh-Robosoft please remove the line with adapter?.setHasStableIds(true) from FirstFragment and add:

override fun getItemViewType(position: Int): Int {
    return position
}

to your adapter code. That should help.

Nagesh-Robosoft commented 2 years ago

@soommy12 Thanks for the response. The solution worked for single view type as in the demo application. But we cannot apply the same solution for the multiple view type. Can you please help on same.

soommy12 commented 2 years ago

@Nagesh-Robosoft sure. Can you please update your demo project (or create a new one) and apply the same logic you have in your real project? That would be very helpful for me. Because at this moment I cannot propose anything more than I already did. Maybe the root of the problem is somewhere else.

Nagesh-Robosoft commented 2 years ago

@soommy12 Sure. Update demo app : https://drive.google.com/file/d/1YxDeB9nq16WLLyGg0q411G4iw238MhK6/view?usp=sharing Issue link: https://drive.google.com/file/d/1pqPCgVEb4U8Vul4LM5-T4Td2NENnL78u/view?usp=sharing Let me know if you need any other inputs. Thank you.

soommy12 commented 2 years ago

@Nagesh-Robosoft I debugged your project and it looks like the library has some problems with reusing the view holders when a recycler view is supplied with more than one type. We are investigating what could be the cause. I will provide a proper solution as soon as possible. Thanks for reporting this issue.

Nagesh-Robosoft commented 2 years ago

Hi @soommy12 , Hope you are doing good. It would be great if I know the progress on the issue or the approximate date for the fix. Our release date is closer we need fix this issue as soon as possible since its a blocker issue. Your effort and time is really appreciated. Thank you.

soommy12 commented 2 years ago

Hi @Nagesh-Robosoft ! Sorry for the late response, there was a holiday break in my country. We are working on the issue but we didn't find a fitting solution yet. There is no ETA for that yet.

MikolajMichalczak commented 6 months ago

Hi @Nagesh-Robosoft!

Apologies for the delayed response. I've updated your provided sample project, specifically upgrading the library version to 11.2.0. While addressing the issue related to loading incorrect data within the RecyclerView and chart discrepancies during recycling, I restructured the ViewHolder code.

The revamped ViewHolder now efficiently initializes crucial, immutable properties during its creation, aiming for optimized setup and improved performance. During the bind() function, only necessary chart data is dynamically updated based on the provided Trend object.

Here's the modified code snippet:

class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        private lateinit var trend: Trend
        private var realMadrid: HIColumn
        private var options: HIOptions

        val textView: TextView = itemView.findViewById(R.id.textView)
        private val chartView: HIChartView = itemView.findViewById(R.id.charView)

        init {
            val options = HIOptions()
            val chart = HIChart()
            val hiColor = HIColor.initWithRGBA(0, 0, 0, 0.0)
            chart.backgroundColor = hiColor
            options.chart = chart

            val hiTitle = HITitle()
            hiTitle.text = ""
            options.title = hiTitle

            val yAxis = HIYAxis()
            yAxis.title = HITitle()
            yAxis.title.text = ""
            yAxis.labels = HILabels()
            yAxis.labels.style = HICSSObject()
            yAxis.labels.style.fontSize = "10px"
            //  yAxis.gridLineWidth = ChartsThemeUtil.getGridlinesWidth(requireContext())
            //  yAxis.gridLineColor = HIColor.initWithHexValue(ChartsThemeUtil.getGridlinesColor(requireContext()))
            yAxis.gridLineDashStyle = "Dot"
            //   yAxis.labels.style.color = ChartsThemeUtil.getBarVerTextColorWithtHex(requireContext())
            yAxis.tickLength = 0
            options.yAxis = ArrayList(listOf(yAxis))

            val legend = HILegend()
            legend.enabled = false
            options.legend = legend

            val exporting = HIExporting()
            exporting.enabled = false
            options.exporting = exporting

            val credits = HICredits()
            credits.enabled = false
            options.credits = credits

            val plotOptions = HIPlotOptions()
            plotOptions.column = HIColumn()
            plotOptions.column.pointPadding = 0.05
            plotOptions.column.borderWidth = 0
            plotOptions.column.maxPointWidth = 20
            plotOptions.series = HISeries()

            val realMadrid = HIColumn()
            realMadrid.name = ""
            this.realMadrid = realMadrid
            this.options = options
        }

        fun bindData(trend: Trend) {
            this.trend = trend

            val realMadridData: ArrayList<Any> = ArrayList<Any>()
            realMadridData.add(trend.firstvalue)
            realMadridData.add(trend.secondValue)
            realMadridData.add(trend.thirdvalue)
            realMadridData.add(trend.fourthvalue)
            realMadrid.data = realMadridData

            options.series = ArrayList(listOf(realMadrid))
            chartView.options = options
        }
    }

The approach I've taken in restructuring the ViewHolder code represents a promising method not just within the Highcharts library context, but also as a good practice for RecyclerView and class instantiation within its ViewHolder.

After implementing these modifications, I no longer encountered the reported issue in the provided project. Please integrate this updated code to confirm if it resolves the problem.

Thank you for being so patient and providing the sample project.

MikolajMichalczak commented 2 months ago

Closing due to inactivity. Please feel free to reopen the ticket if you have any further questions or if the problem persists.