\r\n
<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<LinearLayout xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"\r\n xmlns:ap=\"http:\/\/schemas.android.com\/apk\/res-auto\"\r\n style=\"@style\/sample_activity\">\r\n\r\n <com.androidplot.xy.XYPlot\r\n style=\"@style\/simple_xy\"\r\n android:id=\"@+id\/dynamicXYPlot\"\r\n android:layout_width=\"fill_parent\"\r\n android:layout_height=\"fill_parent\"\r\n androidplot.renderMode=\"use_background_thread\"\r\n ap:label=\"A Dynamic XY Plot\"\r\n ap:domainLabel=\"Domain\"\r\n ap:rangeLabel=\"Range\"\r\n ap:legendTextSize=\"15sp\"\r\n ap:legendIconHeight=\"15dp\"\r\n ap:legendIconWidth=\"15dp\"\r\n ap:legendHeight=\"25dp\"\r\n ap:legendAnchorPosition=\"right_bottom\"\/>\r\n\r\n<\/LinearLayout><\/pre>\r\n<\/div>\r\nDynamicXYPlotActivity.java<\/h3>\r\n\r\n
package com.androidplot.demos;\r\nimport android.app.Activity;\r\nimport android.graphics.Color;\r\nimport android.graphics.DashPathEffect;\r\nimport android.graphics.Paint;\r\nimport android.os.Bundle;\r\nimport com.androidplot.Plot;\r\nimport com.androidplot.util.PixelUtils;\r\nimport com.androidplot.xy.XYSeries;\r\nimport com.androidplot.xy.*;\r\n\r\nimport java.text.DecimalFormat;\r\nimport java.util.Observable;\r\nimport java.util.Observer;\r\n\r\npublic class DynamicXYPlotActivity extends Activity {\r\n\r\n \/\/ redraws a plot whenever an update is received:\r\n private class MyPlotUpdater implements Observer {\r\n Plot plot;\r\n\r\n public MyPlotUpdater(Plot plot) {\r\n this.plot = plot;\r\n }\r\n\r\n @Override\r\n public void update(Observable o, Object arg) {\r\n plot.redraw();\r\n }\r\n }\r\n\r\n private XYPlot dynamicPlot;\r\n private MyPlotUpdater plotUpdater;\r\n SampleDynamicXYDatasource data;\r\n private Thread myThread;\r\n\r\n @Override\r\n public void onCreate(Bundle savedInstanceState) {\r\n\r\n \/\/ android boilerplate stuff\r\n super.onCreate(savedInstanceState);\r\n setContentView(R.layout.dynamicxyplot_example);\r\n\r\n \/\/ get handles to our View defined in layout.xml:\r\n dynamicPlot = (XYPlot) findViewById(R.id.dynamicXYPlot);\r\n\r\n plotUpdater = new MyPlotUpdater(dynamicPlot);\r\n\r\n \/\/ only display whole numbers in domain labels\r\n dynamicPlot.getGraphWidget().setDomainValueFormat(new DecimalFormat(\"0\"));\r\n\r\n \/\/ getInstance and position datasets:\r\n data = new SampleDynamicXYDatasource();\r\n SampleDynamicSeries sine1Series = new SampleDynamicSeries(data, 0, \"Sine 1\");\r\n SampleDynamicSeries sine2Series = new SampleDynamicSeries(data, 1, \"Sine 2\");\r\n\r\n LineAndPointFormatter formatter1 = new LineAndPointFormatter(\r\n Color.rgb(0, 0, 0), null, null, null);\r\n formatter1.getLinePaint().setStrokeJoin(Paint.Join.ROUND);\r\n formatter1.getLinePaint().setStrokeWidth(10);\r\n dynamicPlot.addSeries(sine1Series,\r\n formatter1);\r\n\r\n LineAndPointFormatter formatter2 =\r\n new LineAndPointFormatter(Color.rgb(0, 0, 200), null, null, null);\r\n formatter2.getLinePaint().setStrokeWidth(10);\r\n formatter2.getLinePaint().setStrokeJoin(Paint.Join.ROUND);\r\n\r\n \/\/formatter2.getFillPaint().setAlpha(220);\r\n dynamicPlot.addSeries(sine2Series, formatter2);\r\n\r\n \/\/ hook up the plotUpdater to the data model:\r\n data.addObserver(plotUpdater);\r\n\r\n \/\/ thin out domain tick labels so they dont overlap each other:\r\n dynamicPlot.setDomainStepMode(XYStepMode.INCREMENT_BY_VAL);\r\n dynamicPlot.setDomainStepValue(5);\r\n\r\n dynamicPlot.setRangeStepMode(XYStepMode.INCREMENT_BY_VAL);\r\n dynamicPlot.setRangeStepValue(10);\r\n\r\n dynamicPlot.setRangeValueFormat(new DecimalFormat(\"###.#\"));\r\n\r\n \/\/ uncomment this line to freeze the range boundaries:\r\n dynamicPlot.setRangeBoundaries(-100, 100, BoundaryMode.FIXED);\r\n\r\n \/\/ create a dash effect for domain and range grid lines:\r\n DashPathEffect dashFx = new DashPathEffect(\r\n new float[] {PixelUtils.dpToPix(3), PixelUtils.dpToPix(3)}, 0);\r\n dynamicPlot.getGraphWidget().getDomainGridLinePaint().setPathEffect(dashFx);\r\n dynamicPlot.getGraphWidget().getRangeGridLinePaint().setPathEffect(dashFx);\r\n }\r\n @Override\r\n public void onResume() {\r\n \/\/ kick off the data generating thread:\r\n myThread = new Thread(data);\r\n myThread.start();\r\n super.onResume();\r\n }\r\n\r\n @Override\r\n public void onPause() {\r\n data.stopThread();\r\n super.onPause();\r\n }\r\n\r\n class SampleDynamicXYDatasource implements Runnable {\r\n\r\n \/\/ encapsulates management of the observers watching this datasource for update events:\r\n class MyObservable extends Observable {\r\n @Override\r\n public void notifyObservers() {\r\n setChanged();\r\n super.notifyObservers();\r\n }\r\n }\r\n\r\n private static final double FREQUENCY = 5; \/\/ larger is lower frequency\r\n private static final int MAX_AMP_SEED = 100;\r\n private static final int MIN_AMP_SEED = 10;\r\n private static final int AMP_STEP = 1;\r\n public static final int SINE1 = 0;\r\n public static final int SINE2 = 1;\r\n private static final int SAMPLE_SIZE = 30;\r\n private int phase = 0;\r\n private int sinAmp = 1;\r\n private MyObservable notifier;\r\n private boolean keepRunning = false;\r\n\r\n {\r\n notifier = new MyObservable();\r\n }\r\n\r\n public void stopThread() {\r\n keepRunning = false;\r\n }\r\n\r\n \/\/@Override\r\n public void run() {\r\n try {\r\n keepRunning = true;\r\n boolean isRising = true;\r\n while (keepRunning) {\r\n\r\n Thread.sleep(10); \/\/ decrease or remove to speed up the refresh rate.\r\n phase++;\r\n if (sinAmp >= MAX_AMP_SEED) {\r\n isRising = false;\r\n } else if (sinAmp <= MIN_AMP_SEED) {\r\n isRising = true;\r\n }\r\n\r\n if (isRising) {\r\n sinAmp += AMP_STEP;\r\n } else {\r\n sinAmp -= AMP_STEP;\r\n }\r\n notifier.notifyObservers();\r\n }\r\n } catch (InterruptedException e) {\r\n e.printStackTrace();\r\n }\r\n }\r\n\r\n public int getItemCount(int series) {\r\n return SAMPLE_SIZE;\r\n }\r\n\r\n public Number getX(int series, int index) {\r\n if (index >= SAMPLE_SIZE) {\r\n throw new IllegalArgumentException();\r\n }\r\n return index;\r\n }\r\n\r\n public Number getY(int series, int index) {\r\n if (index >= SAMPLE_SIZE) {\r\n throw new IllegalArgumentException();\r\n }\r\n double angle = (index + (phase))\/FREQUENCY;\r\n double amp = sinAmp * Math.sin(angle);\r\n switch (series) {\r\n case SINE1:\r\n return amp;\r\n case SINE2:\r\n return -amp;\r\n default:\r\n throw new IllegalArgumentException();\r\n }\r\n }\r\n\r\n public void addObserver(Observer observer) {\r\n notifier.addObserver(observer);\r\n }\r\n\r\n public void removeObserver(Observer observer) {\r\n notifier.deleteObserver(observer);\r\n }\r\n\r\n }\r\n\r\n class SampleDynamicSeries implements XYSeries {\r\n private SampleDynamicXYDatasource datasource;\r\n private int seriesIndex;\r\n private String title;\r\n\r\n public SampleDynamicSeries(SampleDynamicXYDatasource datasource, int seriesIndex, String title) {\r\n this.datasource = datasource;\r\n this.seriesIndex = seriesIndex;\r\n this.title = title;\r\n }\r\n\r\n @Override\r\n public String getTitle() {\r\n return title;\r\n }\r\n\r\n @Override\r\n public int size() {\r\n return datasource.getItemCount(seriesIndex);\r\n }\r\n\r\n @Override\r\n public Number getX(int index) {\r\n return datasource.getX(seriesIndex, index);\r\n }\r\n\r\n @Override\r\n public Number getY(int index) {\r\n return datasource.getY(seriesIndex, index);\r\n }\r\n }\r\n}<\/pre>\r\n<\/div>\r\n<\/div>\r\n<\/div>\r\n<\/div>\r\n