我第一次尝试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
元素(和其他UI元素)的整个XYPlot
被完全遮盖。这里发生了什么?
其他问题:据我了解,任何影响Android UI的代码都必须在主线程上运行。但是我们正在使用背景线程来绘制图。这是如何运作的?我是否需要在Observable链中插入.observeOn( AndroidSchedulers.mainThread()
运算符?
答案 0 :(得分:0)
我没有太多同步经验-这看起来合理吗?
我认为您不需要wait()
内同步块内的updatePlotData
。您也可以使用SimpleXYSeries作为如何设置这种同步的参考。
当应用程序首次启动时,“虚拟”图会出现在其视图中,但是当我尝试绘制该图时,包含XYPlot元素(和其他UI元素)的整个ConstraintLayout就会完全被清空。
我很难想象这个。您可以添加“虚拟”图和后续空白图的屏幕截图吗?
据我了解,任何影响Android UI的代码都必须在主线程上运行。但是我们正在使用背景线程来绘制图。如何运作?
使用主线程更新UI的一般规则仍然存在,Androidplot只是使用一种技术来在密集渲染期间最小化主线程使用:背景线程用于将要显示的数据填充到位图缓冲区中,然后在准备显示缓冲区时通知主线程。
一些无关的建议:在您的TempPlotSeries
实现中,我注意到您正在将数据建模为Pair<Date, Float>[]
,但您的getX()
实现并未利用{{1} }部分。看来您正在尝试使用网域假设的显示格式来建模数据。 -60至-1/1/12分钟。为简单起见,我建议使Date
返回Date的长历元值。您可以稍后将显示格式应用于这些值。