后台渲染和UI显示

时间:2018-10-28 21:37:53

标签: android synchronization rx-java androidplot

我第一次尝试AndroidPlot。我要绘制的数据(并在到达新数据点时每5秒更新一次)来自ArrayBlockingQueue,最多可标记720个时间戳点。我有一个实现XYSeriesPlotListener接口的类。它具有方法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()运算符?

1 个答案:

答案 0 :(得分:0)

  

我没有太多同步经验-这看起来合理吗?

我认为您不需要wait()内同步块内的updatePlotData。您也可以使用SimpleXYSeries作为如何设置这种同步的参考。

  

当应用程序首次启动时,“虚拟”图会出现在其视图中,但是当我尝试绘制该图时,包含XYPlot元素(和其他UI元素)的整个ConstraintLayout就会完全被清空。

我很难想象这个。您可以添加“虚拟”图和后续空白图的屏幕截图吗?

  

据我了解,任何影响Android UI的代码都必须在主线程上运行。但是我们正在使用背景线程来绘制图。如何运作?

使用主线程更新UI的一般规则仍然存在,Androidplot只是使用一种技术来在密集渲染期间最小化主线程使用:背景线程用于将要显示的数据填充到位图缓冲区中,然后在准备显示缓冲区时通知主线程。

一些无关的建议:在您的TempPlotSeries实现中,我注意到您正在将数据建模为Pair<Date, Float>[],但您的getX()实现并未利用{{1} }部分。看来您正在尝试使用网域假设的显示格式来建模数据。 -60至-1/1/12分钟。为简单起见,我建议使Date返回Date的长历元值。您可以稍后将显示格式应用于这些值。