PhilJay / MPAndroidChart

A powerful 🚀 Android chart view / graph view library, supporting line- bar- pie- radar- bubble- and candlestick charts as well as scaling, panning and animations.
Other
37.53k stars 9.01k forks source link

Endless loop in DataSet.getEntryIndex for specific data #2885

Open fkirc opened 7 years ago

fkirc commented 7 years ago

My application got stuck in an endless loop when attempting to display specific data sets in a line chart. I started the debugger and figured out using thread dumps that the main thread got stuck in the following method:

@Override, DataSet.Java Line 289 public int getEntryIndex(float xValue, float closestToY, Rounding rounding) {

This is the endless loop in DataSet.java:

while (low < high) {
            int m = (low + high) / 2;

            final float d1 = mValues.get(m).getX() - xValue,
                    d2 = mValues.get(m + 1).getX() - xValue,
                    ad1 = Math.abs(d1), ad2 = Math.abs(d2);

            if (ad2 < ad1) {
                // [m + 1] is closer to xValue
                // Search in an higher place
                low = m + 1;
            } else if (ad1 < ad2) {
                // [m] is closer to xValue
                // Search in a lower place
                high = m;
            } else {
                // We have multiple sequential x-value with same distance

                if (d1 >= 0.0) {
                    // Search in a lower place
                    high = m;
                } else if (d1 < 0.0) {
                    // Search in an higher place
                    low = m + 1;
                }
            }

            closest = high;
        }

Here is a snapshot of the thread state:

java.lang.Thread.State: RUNNABLE at com.github.mikephil.charting.data.DataSet.getEntryIndex(DataSet.java:299) at com.github.mikephil.charting.data.DataSet.getEntryForXValue(DataSet.java:273) at com.github.mikephil.charting.renderer.BarLineScatterCandleBubbleRenderer$XBounds.set(BarLineScatterCandleBubbleRenderer.java:88) at com.github.mikephil.charting.renderer.LineChartRenderer.drawLinear(LineChartRenderer.java:312) at com.github.mikephil.charting.renderer.LineChartRenderer.drawDataSet(LineChartRenderer.java:114) at com.github.mikephil.charting.renderer.LineChartRenderer.drawData(LineChartRenderer.java:96) at com.github.mikephil.charting.charts.BarLineChartBase.onDraw(BarLineChartBase.java:229) at android.view.View.draw(View.java:17122)

I can provide more specific information about the used data set if necessary.

fkirc commented 7 years ago

I was able to reliably reproduce the bug:

It happens when a LineChart is used with only one entry and when xAxisMinimum and xAxisMaximum are therefore set to the same value:

if (entries.size() >= 2) {  // check to fix the crash
            final float xMinimum = entries.get(0).getX();
            final float xMaximum = entries.get(entries.size() - 1).getX();
            xAxis.setAxisMinimum(xMinimum);
            xAxis.setAxisMaximum(xMaximum);
            chart.setVisibleXRange(xMinimum, xMaximum);
        }

I fixed the crash using the above check whether entries has two or more entries. Nevertheless I think that this bug should be fixed in the library.

It is still an application not responding crash when xAxisMinimum and xAxisMaximum are set to the same value.