在仔细搜索了正确的工作实用程序之后,我终于放弃并解决了我面临的问题:如何在{{{>>如何呈现异步加载的数据(RPC) 3}}图表本身是通过异步Google Visualization for GWT加载并行执行两个请求吗?
或者换句话说:无论图表数据是在加载Visualization库之前还是之后到达,我们如何确保图表呈现能够正常工作?
两个限制较少(或不那么雄心勃勃)的场景非常简单。
使用Visualization不依赖于RPC数据很简单。这是因为只有一个异步请求:加载Visualization库。因此,在加载Visualization库之前,数据不会到达的风险。
示例代码段:
public class MyViewImpl implements MyView {
private Panel main;
public MyViewImpl() {
this.main = new FlowPanel();
Runnable onVizLoaded = new Runnable() {
@Override
public void run() {
DataTable data = DataTable.create();
Options options = Options.create();
// Populate data and options based on static data here...
// Instantiate and attach new chart.
LineChart lineChart = new LineChart(data, options);
main.add(lineChart);
}
};
// Load Google Visualization asynchronously.
VisualizationUtils.loadVisualizationApi(onVizLoaded, LineChart.PACKAGE);
}
// View logic goes here...
}
可以轻松加载Visualization库,并在加载完成后创建并呈现LineChart
。考虑一下负载特性的概述:
Viz load: |---?---|
Chart data: |
Render: |--->
可以在通过RPC加载图表数据时利用上面的代码段。但是,以下意味着在Visualization库加载并准备好之前,不会获取图表数据。你可能会对这种性能影响感到满意 - 我不是!
示例代码段:
public class MyViewImpl implements MyView {
private Panel main;
public MyViewImpl() {
this.main = new FlowPanel();
Runnable onVizLoaded = new Runnable() {
@Override
public void run() {
// Make RPC call.
ClientFactory.getService().getData(new AsyncCallback<MyResult>() {
@Override
public void onSuccess(MyResult result) {
DataTable data = DataTable.create();
Options options = Options.create();
// Populate data from RPC result.
data.addColumn(ColumnType.DATE);
data.addRow();
data.setValue(0, 0, result.getDate());
// ... Etc.
// Set options.
options.setWidth(500);
// ... Etc.
// Instantiate and attach new chart.
LineChart lineChart = new LineChart(data, options);
main.add(lineChart);
}
@Override
public void onFailure(Throwable caught) {
// Handle RPC error.
}
});
}
};
// Load Google Visualization asynchronously.
VisualizationUtils.loadVisualizationApi(onVizLoaded, LineChart.PACKAGE);
}
// View logic goes here...
}
负载特性说明了问题:
Viz load: |---?---|
Chart data: |----~----|
Render: |--->
所需方案将具有以下特征,可视化库的加载速度比数据快:
Viz load: |---?---|
Chart data: |----~----|
Render: |--->
或者数据加载速度比可视化库快:
Viz load: |---?---|
Chart data: |--~--|
Render: |--->
问题是:如何?
答案 0 :(得分:0)
以下策略将符合要求:
示例代码段:演示者
public class MyPresenter implements MyView.Presenter {
private MyView view;
// ... Constructor etc. goes here...
@Override
public void render() {
// Make RPC call immediately when Presenter should begin rendering.
ClientFactory.getService().getData(new AsyncCallback<MyResult>() {
@Override
public void onSuccess(MyResult result) {
// Pass data to view for rendering (when appropriate.)
view.render(result);
}
@Override
public void onFailure(Throwable caught) {
// Handle RPC error.
}
});
}
}
示例代码段:ViewImpl
public class MyViewImpl implements MyView {
private Panel main;
private AsyncChart<LineChart> asyncLineChart;
public MyViewImpl() {
this.main = new FlowPanel();
// Runnable wrapper (see next snippet.)
this.asyncLineChart = new AsyncChart<LineChart>() {
@Override
public LineChart onAttach(DataTable data, Options options) {
// Instantiate and attach new chart.
LineChart lineChart = new LineChart(data, options);
main.add(lineChart);
return lineChart;
}
};
// Load Google Visualization asynchronously.
VisualizationUtils.loadVisualizationApi(this.asyncLineChart, LineChart.PACKAGE);
}
@Override
public void render(final MyResult result) { // Invoked from Presenter (see above snippet.)
// Schedule rendering to be invoked ASAP (but not before Visualization library is loaded.)
this.asyncLineChart.enqueueWriter(new AsyncChartWriter() {
@Override
public void onWrite(DataTable data, Options options) {
// Populate data from RPC result.
data.addColumn(ColumnType.DATE);
data.addRow();
data.setValue(0, 0, result.getDate());
// ... Etc.
// Set options.
options.setWidth(500);
// ... Etc.
}
});
}
}
现在为了肉!
示例代码段:AsyncChart 准备复制。
import com.google.gwt.visualization.client.DataTable;
import com.google.gwt.visualization.client.VisualizationUtils;
import com.google.gwt.visualization.client.visualizations.corechart.CoreChart;
import com.google.gwt.visualization.client.visualizations.corechart.Options;
/**
* Wrapping {@link Runnable} to use with the load methods of {@link VisualizationUtils}
* allowing a chart to be populated asynchronously (e.g., via RPC.)
*
* This wrapper handles the process of deferred attachment of the chart via the
* {@link #onAttach(DataTable, Options)} method.
*
* Chart data is set / updated by means of a {@link AsyncChartWriter} mutating the
* passed {@link DataTable} and {@link Options} instances.
*
* {@link AsyncChartWriter} can be reassigned (via {@link #enqueueWriter(AsyncChartWriter)})
* in order to redraw the chart.
*
* @param <T> The concrete chart type.
*/
public abstract class AsyncChart<T extends CoreChart> implements Runnable {
public interface AsyncChartWriter {
void onWrite(DataTable data, Options options);
}
private enum State {
NEW,
LOADED,
ATTACHED
}
private State state;
private T chart;
private AsyncChartWriter enqueuedWriter;
public AsyncChart() {
this.state = State.NEW;
}
public abstract T onAttach(DataTable data, Options options);
/**
* Enqueues a writer to populate or manipulate the chart. This will happen immediately
* if the visualization API is already loaded and will otherwise be deferred.
*
* @param writer The writer to enqueue.
*/
public void enqueueWriter(AsyncChartWriter writer) {
this.enqueuedWriter = writer;
processWriter();
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*
* Invoked when the visualization API has loaded.
*/
@Override
public void run() {
this.state = State.LOADED;
if (this.enqueuedWriter != null) {
processWriter();
}
}
private void processWriter() {
if (this.state == State.LOADED || this.state == State.ATTACHED) {
DataTable data = DataTable.create();
Options options = CoreChart.createOptions();
this.enqueuedWriter.onWrite(data, options);
if (this.state == State.LOADED) {
this.chart = onAttach(data, options); // Instantiate and attach.
this.state = State.ATTACHED;
} else {
this.chart.draw(data, options); // Redraw already attached chart.
}
this.enqueuedWriter = null;
}
// If state = NEW do nothing until run() is invoked (and state has changed to LOADED.)
}
}
享受并行负载。