Сбой графика в реальном времени MPAndroidChart - PullRequest
0 голосов
/ 26 мая 2020

Я пытаюсь создать пример приложения Android с помощью MPAndroidPlot для построения графиков некоторых случайных данных в реальном времени. Я пытаюсь заставить приложение вести себя следующим образом:

  1. Поток вызывает addEntry, засыпает некоторое время и повторяет
  2. addEntry добавляет запись. Если количество записей превышает предварительно определенное максимальное количество записей, он удалит первую запись и сдвинет все остальные записи влево на одну единицу перед добавлением новой записи.

Вот код Ниже я объясню проблему.

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "SCOPEN";

    private static final int MAX_SAMPLES = 100;
    private static final int BG_COLOR = 0xFF47474E;
    private static final int LINE_COLOR = 0xFFFFFACD;

    private float mTimeStep = 0.5f;
    private float mMaxY = 10;
    private float mMinY = 0;

    private LineChart mChart;
    private LineDataSet mDataSet;
    private LineData mLineData;

    @SuppressLint("SourceLockedOrientationActivity")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        setContentView(R.layout.activity_main);

        // Configure graph
        mChart = (LineChart) findViewById(R.id.chart);
        mChart.setHardwareAccelerationEnabled(true);
        mChart.setBackgroundColor(BG_COLOR);
        mChart.setDescription(null);
        mChart.setAutoScaleMinMaxEnabled(false);
        mChart.setPinchZoom(false);
        mChart.setDragEnabled(true);
        mChart.setScaleEnabled(true);
        mChart.setTouchEnabled(false);

        // Disable legend
        Legend legend = mChart.getLegend();
        legend.setEnabled(false);

        // Configure y-axis right
        mChart.getAxisRight().setEnabled(false);

        // Configure y-axis left
        YAxis yAxisLeft = mChart.getAxisLeft();
        yAxisLeft.setDrawGridLines(true);
        yAxisLeft.setDrawAxisLine(false);
        yAxisLeft.setDrawLabels(false);
        yAxisLeft.setAxisMinimum(mMinY);
        yAxisLeft.setAxisMaximum(mMaxY);
        //yAxisLeft.enableGridDashedLine(10, 0, 0);

        // Configure x-axis
        XAxis xAxis = mChart.getXAxis();
        xAxis.setDrawGridLines(true);
        xAxis.setDrawAxisLine(false);
        xAxis.setDrawLabels(false);
        xAxis.setAxisMinimum(0);
        xAxis.setAxisMaximum(mTimeStep * (MAX_SAMPLES - 1));
        //xAxis.enableGridDashedLine(10, 10, 0);

        // Configure data
        mDataSet = new LineDataSet(null, null);
        mDataSet.setDrawValues(false);
        mDataSet.setColor(LINE_COLOR);
        mDataSet.setCircleColor(LINE_COLOR);
        mDataSet.setLineWidth(3f);
        mDataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);

        mLineData = new LineData(mDataSet);
        mChart.setData(mLineData);
        mChart.invalidate();

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    addEntry(new Random().nextInt(10));
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        thread.start();
    }

    public void addEntry(final float v) {
        if (mDataSet.getEntryCount() == MAX_SAMPLES) {
            mDataSet.removeFirst();
            for (Entry entry : mDataSet.getValues()) {
                entry.setX(entry.getX() - mTimeStep);
            }
        }
        mDataSet.addEntry(new Entry(mDataSet.getEntryCount() * mTimeStep, v));
        mDataSet.notifyDataSetChanged();
        mLineData.notifyDataChanged();
        mChart.notifyDataSetChanged();
        mChart.invalidate();
    }
}

Проблема: мое приложение вылетает через случайный промежуток времени. Уменьшение времени ожидания потока, порождающего вход, ускоряет время до cra sh (<50 мс обычно приводит к постоянному cra sh в течение 10 секунд). </p>

Ошибка:

2020-05-25 21:58:32.241 18392-18392/com.example.scopen E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.scopen, PID: 18392
    java.lang.IndexOutOfBoundsException: Index: 99, Size: 100
        at java.util.ArrayList.get(ArrayList.java:437)
        at com.github.mikephil.charting.data.DataSet.getEntryForIndex(DataSet.java:294)
        at com.github.mikephil.charting.renderer.LineChartRenderer.drawCircles(LineChartRenderer.java:667)
        at com.github.mikephil.charting.renderer.LineChartRenderer.drawExtras(LineChartRenderer.java:601)
        at com.github.mikephil.charting.charts.BarLineChartBase.onDraw(BarLineChartBase.java:255)
        at android.view.View.draw(View.java:23190)
        at android.view.View.updateDisplayListIfDirty(View.java:22065)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:5214)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:5186)
        at android.view.View.updateDisplayListIfDirty(View.java:22020)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:5214)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:5186)
        at android.view.View.updateDisplayListIfDirty(View.java:22020)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:5214)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:5186)
        at android.view.View.updateDisplayListIfDirty(View.java:22020)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:5214)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:5186)
        at android.view.View.updateDisplayListIfDirty(View.java:22020)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:5214)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:5186)
        at android.view.View.updateDisplayListIfDirty(View.java:22020)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:5214)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:5186)
        at android.view.View.updateDisplayListIfDirty(View.java:22020)
        at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:588)
        at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:594)
        at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:667)
        at android.view.ViewRootImpl.draw(ViewRootImpl.java:4263)
        at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:4047)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3320)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2200)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9065)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:999)
        at android.view.Choreographer.doCallbacks(Choreographer.java:797)
        at android.view.Choreographer.doFrame(Choreographer.java:732)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:984)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:237)
        at android.app.ActivityThread.main(ActivityThread.java:8016)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1076)

Обратите внимание, что я получаю IndexOutOfBoundsException, где попытка доступа к индексу меньше размера ArrayList. Я пробовал использовать несколько разных максимальных размеров, и индекс всегда имеет размер - 1. Я подозреваю, что есть какая-то проблема с параллелизмом. Возможно, когда вызывается mChart.invalidate(), он заставляет экран обновлять sh. Затем существует вероятность состояния, в котором поток удаляет значение так же, как дисплей пытается прочитать последнее значение.

Я не эксперт по java или Android, поэтому буду благодарен за любую помощь. Спасибо!

...