我一直在问一系列关于我的Android项目的不断演变的问题,这些问题不断地实时绘制蓝牙数据。我在提问方面做得不是很好。所以我需要做的是编辑这个问题,清理它,添加重要的细节,最重要的是我需要添加相关代码段的代码片段,特别是我已经砍掉很多的段落,以及提供有关这些代码段的解释。这样,也许我可能会得到一个答案,我的问题是:我目前的解决方案是否可行?当我添加新功能时,它会持续吗?Android静态方法实时绘制后台线程数据很好,但它是一个很好的解决方案吗?
基本上我已经完成的是通过将一些开源代码Blueterm和OrientationSensor组合在一起来创建我的应用程序的第一个版本。
有人建议我添加一个线程,一个处理程序,一个服务或者使用异步任务或AIDL等。但是我决定我不想修改或替换我现有的解决方案,除非我真的应该这样做。主要我想知道它是否足够向前推进并且扩展它可以添加其他功能。
顺便说一下,我之前提到的BluetoothData只是蓝牙数据:它是从远程蓝牙设备以2到10个采样/秒的速率接收的16位数据。我的应用程序基本上是一个获取/接收蓝牙数据并绘制它的数据采集系统。
下面是我开始使用的Blueterm开放源代码的描述(请参阅上面的链接)。 Blueterm基本上是一个通过蓝牙进行通信的终端仿真器程序。它由Blueterm中最重要的几项活动组成。它发现,配对并连接支持SPP/RfComm的远程蓝牙设备。连接后,我可以使用Blueterm通过发送命令来打开采样,改变采样通道的数量(改为一个通道),改变输入数据的格式(我喜欢逗号分隔的数据)等等来配置远程设备
下面是我开始使用的OrientationSensorExample开放源代码的描述(请参阅上面的链接)。它基本上是AnroidPlot库的一个示例应用程序。 OrientationSensor活动实现SensorEventListener。这包括覆盖onSenorChanged(),无论何时取得新的方向传感器数据,都会调用onSenorChanged(),并重新绘制图形。
将这两个开放源代码项目(Blueterm和OrientationSensorExample)拼凑在一个应用程序(Blueterm)中后,这里描述了整个应用程序(Blueterm)的工作方式。当我启动Blueterm时,整个屏幕模拟一个漂亮的蓝色终端。从选项菜单中,我发现,配对,连接并配置远程蓝牙设备,如上所述。配置好远程设备后,我再次进入选项菜单并选择启动绘图活动的“绘图数据”。终端模拟器消失了,并且Plot活动出现了一个很好的滚动实时图。
以下是我如何做到这一点。在onOptionsItemSelected()我添加的情况下,推出绘图活动如下:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.connect:
if (getConnectionState() == BluetoothSerialService.STATE_NONE) {
// Launch the DeviceListActivity to see devices and do scan
Intent serverIntent = new Intent(this, DeviceListActivity.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
}
else
if (getConnectionState() == BluetoothSerialService.STATE_CONNECTED) {
mSerialService.stop();
mSerialService.start();
}
return true;
case R.id.preferences:
doPreferences();
return true;
case R.id.menu_special_keys:
doDocumentKeys();
return true;
case R.id.plot_data:
doPlotData();
return true;
}
return false;
}
private void doPlotData() {
Intent plot_data = new Intent(this, com.vtrandal.bluesentry.Plot.class);
startActivity(plot_data);
}
然后在蓝牙后台线程我添加了一个调用的update()调用plotData()如下:
/**
* Look for new input from the ptty, send it to the terminal emulator.
*/
private void update() {
int bytesAvailable = mByteQueue.getBytesAvailable();
int bytesToRead = Math.min(bytesAvailable, mReceiveBuffer.length);
try {
int bytesRead = mByteQueue.read(mReceiveBuffer, 0, bytesToRead);
append(mReceiveBuffer, 0, bytesRead);
//VTR use existing handler that calls update() to get data into plotting activity
//OrientationSensor orientationSensor = new OrientationSensor();
Plot.plotData(mReceiveBuffer, 0, bytesRead);
} catch (InterruptedException e) {
//VTR OMG their swallowing this exception
}
}
然后在Plot活动中,我基本上清理了房屋,删除了“implements SensorEventListener”和一些相关的方法和变量,并写了plotData()以如上所示调用。下面是plotData()和它的辅助方法splitData()和nowPlotData()现在的样子:
private static StringBuffer strData = new StringBuffer("");
public static void plotData(byte[] buffer, int base, int length) {
Log.i("Entering: ", "plotData()");
/*
byte[] buffer = (byte[]) msg.obj;
int base = msg.arg1;
int length = msg.arg2;
*/
for (int i = 0; i < length; i++) {
byte b = buffer[base + i];
try {
if (true) {
char printableB = (char) b;
if (b < 32 || b > 126) {
printableB = ' ';
}
Log.w("Log_plotData", "'" + Character.toString(printableB)
+ "' (" + Integer.toString(b) + ")");
strData.append(Character.toString(printableB));
if (b == 10)
{
Log.i("End of line: ", "processBlueData()");
Log.i("strData", strData.toString());
splitData(strData);
strData = new StringBuffer("");
}
}
} catch (Exception e) {
Log.e("Log_plotData_exception", "Exception while processing character "
+ Integer.toString(i) + " code "
+ Integer.toString(b), e);
}
}
Log.i("Leaving: ", "plotData()");
}
private static void splitData(StringBuffer strBuf) {
String strDash = strBuf.toString().trim();
String[] strDashSplit = strDash.split("-");
for (int ndx = 0; ndx < strDashSplit.length; ndx++)
{
if (strDashSplit[ndx].length() > 0)
Log.i("strDashSplit", ndx + ":" + strDashSplit[ndx]);
String strComma = strDashSplit[ndx].trim();
String[] strCommaSplit = strComma.split(",");
for (int mdx = 0; mdx < strCommaSplit.length; mdx++)
{
if (strCommaSplit[mdx].length() > 0)
Log.i("strCommaSplit", mdx + ":" + strCommaSplit[mdx]);
if (mdx == 1)
{
int raw = Integer.parseInt(strCommaSplit[1],16);
Log.i("raw", Integer.toString(raw));
float rawFloat = raw;
Log.i("rawFloat", Float.toString(rawFloat));
float ratio = (float) (rawFloat/65535.0);
Log.i("ratio", Float.toString(ratio));
float voltage = (float) (5.0*ratio);
Log.i("voltage", Float.toString(voltage));
nowPlotData(voltage);
}
}
}
}
public static void nowPlotData(float data) {
// get rid the oldest sample in history:
if (plotHistory.size() > HISTORY_SIZE) {
plotHistory.removeFirst();
}
// add the latest history sample:
plotHistory.addLast(data);
// update the plot with the updated history Lists:
plotHistorySeries.setModel(plotHistory, SimpleXYSeries.ArrayFormat.Y_VALS_ONLY);
//VTR null pointer exception?
if (plotHistoryPlot == null)
Log.i("aprHistoryPlot", "null pointer exception");
// redraw the Plots:
plotHistoryPlot.redraw();
}
时间作一个总结:我发现基本上在由Blueterm创建的后台线程的update()方法活动。 update()方法实质上是使用append()方法将新接收到的蓝牙数据附加到屏幕缓冲区。所以,后台线程的update()方法看起来像一个调用plotPlot()的好地方。所以我设计了plotData()来绘制传递给append()的数据。只要plotData()是一个静态方法,就可以工作。我希望能解释为什么plotData()看起来必须是静态的才能工作。
而且我的整体问题/顾虑:我目前的解决方案是否可行?当我添加新功能时,它会持续吗?
@CommonsWare我很抱歉没有发布源代码。我不记得任何人要求。但我没有发布链接到代码。它包含一个3300+行文件,我不确定任何人想看到的部分。这里是链接[Blueterm](http://pymasde.es/blueterm/)和[OrientatioinSensor](http://androidplot.com/wiki/OrientationSensorExample)。正如你所看到的,我对开源代码进行了黑客攻击。我将编辑我的问题以解释我对设计的理解,并且我将尝试发布源代码的相关部分。但在此之前,我应该解决您的其他意见。 – Vince 2011-06-04 19:05:17
@CommonsWare我很抱歉,“这个故事没有加起来。“当我编辑我的问题时,我会纠正这个问题,但按照我看到的方式,这个开源代码由3个主要组件组成:蓝牙活动,由蓝牙活动创建的后台线程和绘图活动 – Vince 2011-06-04 19:23:18
@Vince:诚然,没有人特别要求提供源代码,但是,你提出的问题是提供足够的信息来获得你想要的答案。如果你在StackOverflow中寻找答案,你会发现许多问题在源代码发布后关于他们的源代码是否“脆弱”等问题,你可以给我们提供的越多,获得更好答案的几率就越高 – CommonsWare 2011-06-04 19:28:57