【错误记录】MPAndroidChart报NegativeArraySizeException: -2错误

一、错误记录

当前MPAndroidChart图表的版本信息如下:

    //https://github.com/PhilJay/MPAndroidChart
    implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'

具体报错信息如下:

    java.lang.NegativeArraySizeException: -2
        at com.github.mikephil.charting.utils.Transformer.generateTransformedValuesLine(Transformer.java:178)
        at com.github.mikephil.charting.renderer.LineChartRenderer.drawValues(LineChartRenderer.java:549)
        at com.github.mikephil.charting.charts.BarLineChartBase.onDraw(BarLineChartBase.java:278)

二、问题分析

定位到Transformer处的源码如下:

    /**
     * Transforms an List of Entry into a float array containing the x and
     * y values transformed with all matrices for the LINECHART.
     *
     * @param data
     * @return
     */
    public float[] generateTransformedValuesLine(ILineDataSet data,
                                                 float phaseX, float phaseY,
                                                 int min, int max) {

        final int count = ((int) ((max - min) * phaseX) + 1) * 2;

        if (valuePointsForGenerateTransformedValuesLine.length != count) {
            valuePointsForGenerateTransformedValuesLine = new float[count];
        }
        float[] valuePoints = valuePointsForGenerateTransformedValuesLine;

        for (int j = 0; j < count; j += 2) {

            Entry e = data.getEntryForIndex(j / 2 + min);

            if (e != null) {
                valuePoints[j] = e.getX();
                valuePoints[j + 1] = e.getY() * phaseY;
            } else {
                valuePoints[j] = 0;
                valuePoints[j + 1] = 0;
            }
        }

        getValueToPixelMatrix().mapPoints(valuePoints);

        return valuePoints;
    }

报错位置是
valuePointsForGenerateTransformedValuesLine = new float[count];
这一行,很明显问题出现在count上,
报错的问题是NegativeArraySizeException: -2,数值大小为负数的异常,

定位到报错的位置,下面就继续分析,
count是通过final int count = ((int) ((max - min) * phaseX) + 1) * 2;赋值的,phaseX图表数据执行动画的animator对象的x相位值,那问题很有可能就出在(max - min)上,可能是max小于min的值,相减得到负数导致的,

继续往前查找调用上面方法的位置

    @Override
    public void drawValues(Canvas c) {

        if (isDrawingValuesAllowed(mChart)) {

            List<ILineDataSet> dataSets = mChart.getLineData().getDataSets();

            for (int i = 0; i < dataSets.size(); i++) {

                ILineDataSet dataSet = dataSets.get(i);

                if (!shouldDrawValues(dataSet) || dataSet.getEntryCount() < 1)
                    continue;

                // apply the text-styling defined by the DataSet
                applyValueTextStyle(dataSet);

                Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());

                // make sure the values do not interfear with the circles
                int valOffset = (int) (dataSet.getCircleRadius() * 1.75f);

                if (!dataSet.isDrawCirclesEnabled())
                    valOffset = valOffset / 2;

                mXBounds.set(mChart, dataSet);

                float[] positions = trans.generateTransformedValuesLine(dataSet, mAnimator.getPhaseX(), mAnimator
                        .getPhaseY(), mXBounds.min, mXBounds.max);
                ValueFormatter formatter = dataSet.getValueFormatter();

                MPPointF iconsOffset = MPPointF.getInstance(dataSet.getIconsOffset());
                iconsOffset.x = Utils.convertDpToPixel(iconsOffset.x);
                iconsOffset.y = Utils.convertDpToPixel(iconsOffset.y);

                for (int j = 0; j < positions.length; j += 2) {

                    float x = positions[j];
                    float y = positions[j + 1];

                    if (!mViewPortHandler.isInBoundsRight(x))
                        break;

                    if (!mViewPortHandler.isInBoundsLeft(x) || !mViewPortHandler.isInBoundsY(y))
                        continue;

                    Entry entry = dataSet.getEntryForIndex(j / 2 + mXBounds.min);

                    if (dataSet.isDrawValuesEnabled()) {
                        drawValue(c, formatter.getPointLabel(entry), x, y - valOffset, dataSet.getValueTextColor(j / 2));
                    }

                    if (entry.getIcon() != null && dataSet.isDrawIconsEnabled()) {

                        Drawable icon = entry.getIcon();

                        Utils.drawImage(
                                c,
                                icon,
                                (int)(x + iconsOffset.x),
                                (int)(y + iconsOffset.y),
                                icon.getIntrinsicWidth(),
                                icon.getIntrinsicHeight());
                    }
                }

                MPPointF.recycleInstance(iconsOffset);
            }
        }
    }

mXBounds.min, mXBounds.max获取到的max和min值
mXBounds.set(mChart, dataSet);通过数据源进行赋值的,具体赋值的代码如下:

        /**
         * Calculates the minimum and maximum x values as well as the range between them.
         *
         * @param chart
         * @param dataSet
         */
        public void set(BarLineScatterCandleBubbleDataProvider chart, IBarLineScatterCandleBubbleDataSet dataSet) {
            float phaseX = Math.max(0.f, Math.min(1.f, mAnimator.getPhaseX()));

            float low = chart.getLowestVisibleX();
            float high = chart.getHighestVisibleX();

            Entry entryFrom = dataSet.getEntryForXValue(low, Float.NaN, DataSet.Rounding.DOWN);
            Entry entryTo = dataSet.getEntryForXValue(high, Float.NaN, DataSet.Rounding.UP);

            min = entryFrom == null ? 0 : dataSet.getEntryIndex(entryFrom);
            max = entryTo == null ? 0 : dataSet.getEntryIndex(entryTo);
            range = (int) ((max - min) * phaseX);
        }

min是通过可见范围x的最小值,然后根据这个位置获取数据源对应的点,正常情况下应该是在数组的起始位置
max是通过可见范围x的最大值,然后根据这个位置获取数据源对应的点,正常情况下应该是数组的结束位置

正常情况下max大于min,但是出现NegativeArraySizeException这个错误,应该是max小于了min,min获取的数组中后面的位置,max获取到的是数组中前面的点,意味着添加的数据可能是乱序的,并不是按照x的位置一个一个的添加的,这时候要检查下数据源是否有问题了,排查发下确实存在这样的问题,然后添加判断,根据X轴顺序添加数据点就可以了

三、解决办法

具体解决办法需要打印出x对应的值,看下x值的顺序是否是乱序或者倒序的,根据x的值具体调整

简单的示例如下:

 ArrayList<ILineDataSet> dataSets = new ArrayList<>();
  ArrayList<Entry> entries1 = new ArrayList<>();
  LineDataSet lineDataSet1 = new LineDataSet(entries1,"数量");
   dataSets.add(lineDataSet1);
      
     entries1.add(new Entry(6f,116f);
     entries1.add(new Entry(5f,118f);
     entries1.add(new Entry(4f,116f);
     entries1.add(new Entry(3f,112f);
     entries1.add(new Entry(2f,116f);
     entries1.add(new Entry(1f,110f);

修改为:

 ArrayList<ILineDataSet> dataSets = new ArrayList<>();
  ArrayList<Entry> entries1 = new ArrayList<>();
  LineDataSet lineDataSet1 = new LineDataSet(entries1,"数量");
   dataSets.add(lineDataSet1);

     entries1.add(new Entry(1f,116f);
     entries1.add(new Entry(2f,116f);
     entries1.add(new Entry(3f,116f);
     entries1.add(new Entry(4f,116f);
     entries1.add(new Entry(5f,116f);
     entries1.add(new Entry(6f,116f);

猜你喜欢

转载自blog.csdn.net/Billy_Zuo/article/details/131596669