Skip to content

Commit b26855d

Browse files
committed
HorizontalBarChartActivity with high precision
The problem is invariant generics. BarDataSet is DataSet<BarEntryFloat>, so entries expects MutableList<BarEntryFloat>. Even though BarEntryDouble : BarEntryFloat, MutableList<BarEntryDouble> is not a MutableList<BarEntryFloat> because MutableList is invariant (it's both a producer and consumer). MutableList<T> is invariant in T because it both reads (get() → T) and writes (add(T)). Even though BarEntryDouble : BarEntryFloat, the compiler must reject the assignment to prevent this kind of unsound write: val list: MutableList<BarEntryFloat> = values // if allowed... list.add(BarEntryFloat(1f, 2f)) // would corrupt the original BarEntryDouble list! The @Suppress("UNCHECKED_CAST") cast is safe here because: * JVM erases generics at runtime — both are just MutableList on the heap * BarDataSet only reads entries from the list as BarEntryFloat, and BarEntryDouble IS a BarEntryFloat * Nothing writes a plain BarEntryFloat back into the list through BarDataSet
1 parent 9a8c74e commit b26855d

File tree

1 file changed

+15
-7
lines changed

1 file changed

+15
-7
lines changed

app/src/main/kotlin/info/appdev/chartexample/HorizontalBarChartActivity.kt

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import info.appdev.charting.components.Legend
1919
import info.appdev.charting.components.XAxis.XAxisPosition
2020
import info.appdev.charting.data.BarData
2121
import info.appdev.charting.data.BarDataSet
22+
import info.appdev.charting.data.BarEntryDouble
2223
import info.appdev.charting.data.BarEntryFloat
2324
import info.appdev.charting.data.EntryFloat
2425
import info.appdev.charting.highlight.Highlight
@@ -96,14 +97,14 @@ class HorizontalBarChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartV
9697
private fun setData(count: Int, range: Float) {
9798
val barWidth = 9f
9899
val spaceForBar = 10f
99-
val values = ArrayList<BarEntryFloat>()
100+
val values = ArrayList<BarEntryDouble>()
100101
val sampleValues = getValues(100)
101102

102103
for (i in 0..<count) {
103-
val yValue = sampleValues[i]!!.toFloat() * range
104+
val yValue = sampleValues[i]!! * range
104105
values.add(
105-
BarEntryFloat(
106-
x = i * spaceForBar,
106+
BarEntryDouble(
107+
x = i * spaceForBar.toDouble(),
107108
y = yValue,
108109
icon = ResourcesCompat.getDrawable(resources, R.drawable.star, null)
109110
)
@@ -112,15 +113,21 @@ class HorizontalBarChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartV
112113

113114
val set1: BarDataSet
114115

116+
/*The @Suppress("UNCHECKED_CAST") cast is safe here because:
117+
* JVM erases generics at runtime — both are just MutableList on the heap
118+
* BarDataSet only reads entries from the list as BarEntryFloat, and BarEntryDouble IS a BarEntryFloat
119+
* Nothing writes a plain BarEntryFloat back into the list through BarDataSet*/
115120
if (binding.chart1.barData != null &&
116121
binding.chart1.barData!!.dataSetCount > 0
117122
) {
118123
set1 = binding.chart1.barData!!.getDataSetByIndex(0) as BarDataSet
119-
set1.entries = values
124+
@Suppress("UNCHECKED_CAST")
125+
set1.entries = values as MutableList<BarEntryFloat>
120126
binding.chart1.barData?.notifyDataChanged()
121127
binding.chart1.notifyDataSetChanged()
122128
} else {
123-
set1 = BarDataSet(values, "DataSet 1")
129+
@Suppress("UNCHECKED_CAST")
130+
set1 = BarDataSet(values as MutableList<BarEntryFloat>, "DataSet 1")
124131

125132
set1.isDrawIcons = false
126133

@@ -230,8 +237,9 @@ class HorizontalBarChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartV
230237
private val mOnValueSelectedRectF = RectF()
231238

232239
override fun onValueSelected(entryFloat: EntryFloat, highlight: Highlight) {
240+
val barEntry = entryFloat as BarEntryDouble
233241
val bounds = mOnValueSelectedRectF
234-
binding.chart1.getBarBounds(entryFloat as BarEntryFloat, bounds)
242+
binding.chart1.getBarBounds(barEntry, bounds)
235243

236244
val position = binding.chart1.getPosition(
237245
entryFloat, binding.chart1.barData!!.getDataSetByIndex(highlight.dataSetIndex)?.axisDependency

0 commit comments

Comments
 (0)