Моя первая попытка на AndroidPlot. Данные, которые я хочу нанести на график (и обновлять каждые 5 секунд при получении новой точки данных), поступают с ArrayBlockingQueue
до 720 временных отметок. У меня есть класс, который реализует интерфейсы XYSeries
и PlotListener
. У него есть метод updatePlotData
, который просто извлекает данные из очереди в массив:
class TempPlotSeries implements XYSeries, PlotListener {
private final static String TAG = TempPlotSeries.class.getSimpleName();
private Pair<Date, Float>[] plotArray;
void updatePlotData( ArrayBlockingQueue<Pair<Date, Float>> dataQueue ) throws InterruptedException {
synchronized ( this ) {
wait(); // don't update data until we're notified that current plot is done (& we can get lock)
plotArray = dataQueue.toArray( new Pair[0] );
if( DEBUG ) Log.d( TAG, "updatePlotData run with " + plotArray.length + " data points" );
notifyAll(); // release lock & let other threads know they can continue
}
}
// XYSeries implementation
@Override
public int size( ) {
return plotArray.length;
}
@Override
public Number getX( int index ) {
return (index - HISTORY_BUFFER_SIZE) / (60/TEMP_UPDATE_SECONDS); // e.g., -60 minutes at left edge of graph, -1/12 min at right
}
@Override
public Number getY( int index ) {
return plotArray[index].second; // the temp value
}
@Override
public String getTitle( ) {
return "Temp History";
}
// PlotListener Implementation
@Override
public void onBeforeDraw( Plot source, Canvas canvas ) {
synchronized ( this ) {
try {
wait(); // wait for data updating to finish if it's in progress on another thread
} catch ( InterruptedException e ) {
// unlikely to be interrupted?
}
}
}
// between these 2 calls the plot is redrawn
@Override
public void onAfterDraw( Plot source, Canvas canvas ) {
synchronized ( this ) {
notifyAll( ); // plot done, OK to update data
}
}
}
У меня нет большого опыта с синхронизацией - это выглядит разумно?
Моя настройка сюжета:
tempHistoryPlot = (XYPlot) findViewById(R.id.temp_history);
tempPlotSeries = new TempPlotSeries();
tempHistoryPlot.setRenderMode( Plot.RenderMode.USE_BACKGROUND_THREAD );
tempGraphFormatter = new LineAndPointFormatter(this, R.xml.line_point_formatter_with_labels);
tempHistoryPlot.addSeries(tempPlotSeries, tempGraphFormatter);
tempGraphWidget = tempHistoryPlot.getGraph();
(не удалось найти какую-либо документацию по цели getGraph()
, поэтому не знаю, нужно ли мне это.)
У меня есть Observable
(RxJava), который испускает всю очередь данных, когда доступен новый образец (каждые 5 секунд). Если очередь заполнена, я отбрасываю самое старое значение. Тогда у меня есть:
tempPlotSeries.updatePlotData( newTempHistory );
tempHistoryPlot.redraw();
Но сюжет не нарисован. Когда приложение запускается впервые, в его представлении появляется «фиктивный» график, но как только я пытаюсь нарисовать график, весь ConstraintLayout
, содержащий элемент XYPlot
(и другие элементы пользовательского интерфейса), полностью очищается. Что тут происходит?
Другие вопросы: я понимаю, что любой код, влияющий на пользовательский интерфейс Android, должен выполняться в основном потоке. Но мы используем фоновый поток для визуализации графика. Как это работает? Возможно, мне нужно вставить оператор .observeOn( AndroidSchedulers.mainThread()
в мою цепочку наблюдаемых?