Я пытаюсь создать пример приложения Android с помощью MPAndroidPlot для построения графиков некоторых случайных данных в реальном времени. Я пытаюсь заставить приложение вести себя следующим образом:
- Поток вызывает addEntry, засыпает некоторое время и повторяет
- 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, поэтому буду благодарен за любую помощь. Спасибо!