android - 使用graphview库的Android实时信号不流畅
问题描述
我正在尝试绘制从 arduino 到我的 android 平板电脑的实时信号。我使用电位器进行测试,ADC 采样率为 256Hz。我的问题是在 android 应用程序上绘制的图表不流畅。串行通信工作正常,但绘图不是很好。感觉应用程序滞后,并且随着数据的绘制而进一步滞后。
下面是应用图片
package com.example.ecgauth;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothSocket;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
//import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import com.felhr.usbserial.UsbSerialDevice;
import com.felhr.usbserial.UsbSerialInterface;
import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.GraphView.GraphViewData;
import com.jjoe64.graphview.GraphView.LegendAlign;
import com.jjoe64.graphview.GraphViewSeries;
import com.jjoe64.graphview.GraphViewSeries.GraphViewStyle;
import com.jjoe64.graphview.LineGraphView;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends Activity implements View.OnClickListener{
private static final String ACTION_USB_PERMISSION = "com.example.ecg.USB_PERMISSION";
TextView hr_value_text;
UsbDevice device;
UsbDeviceConnection connection;
UsbManager usbManager;
UsbSerialDevice serialPort;
PendingIntent pendingIntent;
// private Handler mHandler;
public static final int MESSAGE_FROM_SERIAL_PORT = 0;
final static int gMAX_BLOCKS = 32; //Maximum blocks
final static int gMAX_SAMPLES = 8; //'Maximum samples
final static int gMAX_CHANNELS = 4; //'Maximum channels
final static int gSampFreq = 256; //Sampling frequency
final static int gRawBufferSize = gMAX_BLOCKS * gMAX_SAMPLES ;
final static float swpfactor = 0;
final static int gSec =0;
int sample =0;
private static boolean acq1 = false;
static int block =0;
int g_intRawBuffer[][] = new int[gMAX_BLOCKS][gMAX_SAMPLES];
double g_sngDnOutBuf[] = new double[gMAX_SAMPLES ];
@Override
public void onBackPressed() {
// // TODO Auto-generated method stub
// if (Bluetooth.connectedThread != null) {
// Bluetooth.connectedThread.write("Q");}//Stop streaming
super.onBackPressed();
}
//toggle Button
static boolean Lock;//whether lock the x-axis to 0-5
static boolean AutoScrollX;//auto scroll to the last x value
static boolean Stream;//Start or stop streaming
int old_interval=0;
int new_interval=0;
int mean_interval=20;
//Button init
Button bXminus;
Button bXplus;
ToggleButton tbLock;
ToggleButton tbScroll;
ToggleButton tbStream;
boolean startthread = true;
//GraphView init
static LinearLayout GraphView;
static GraphView graphView;
static GraphViewSeries Series;
//graph value
private static double graph2LastXValue = 0;
private static int Xview=1023;
Button bConnect, bDisconnect;
private TextView connectionstatus;
public int control_a = 0;
public int TotalSample=0;
char chdata = 0;
int i =0;
String finaldata = "";
String rawdata = "";
byte highbyte=0;
int data = 0 ;
int plotdata = 0 ;
int databuff = 0;
public int[] buffer_bt = new int[768];
public int[] copy_buffer_bt = new int[768];
public int ind_bt = 0;
UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() { //Defining a Callback which triggers whenever data is read.
@Override
public void onReceivedData(byte[] arg0) {
// lowbyte = arg0;
// highbyte = arg0;
byte[] buffer = arg0;
for (int i = 0; i <= (buffer.length - 1); i++) {
if (buffer[i] != 13) {
if (buffer[i] == 10) {
finaldata = rawdata;
rawdata = "";
} else {
chdata = (char) buffer[i];
rawdata += chdata;
}
}
}
data = Integer.parseInt(finaldata);
mHandler.obtainMessage(MESSAGE_FROM_SERIAL_PORT, data).sendToTarget();
control_a = 1;
buffer_bt[databuff] = data;
// }
//lowbyte = buffer;
//highbyte = buffer;
databuff = databuff + 1;
if (databuff == 767){
databuff=0;
}
//
// for (int uu=0; uu<=767; uu++) {
// copy_buffer_bt[uu] = buffer_bt[uu];
// }
// databuff=0;
// ready_bt=1;
// threadon = true;
// }
}
};
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(broadcastReceiver);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
requestWindowFeature(Window.FEATURE_NO_TITLE);//Hide title
this.getWindow().setFlags(WindowManager.LayoutParams.
FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);//Hide Status bar
setContentView(R.layout.activity_main);
//set background color
LinearLayout background = (LinearLayout)findViewById(R.id.bg);
background.setBackgroundColor(Color.BLACK);
// mHandler = new Handler();
//GraphView = (LinearLayout) findViewById(R.id.Graph);
usbManager = (UsbManager) getSystemService(this.USB_SERVICE);
connectionstatus = (TextView) findViewById(R.id.tvBluetooth);
bConnect = (Button)findViewById(R.id.bConnect);
bConnect.setOnClickListener(this);
bDisconnect = (Button)findViewById(R.id.bDisconnect);
bDisconnect.setOnClickListener(this);
//X-axis control button
bXminus = (Button)findViewById(R.id.bXminus);
bXminus.setOnClickListener(this);
bXplus = (Button)findViewById(R.id.bXplus);
bXplus.setOnClickListener(this);
//
tbLock = (ToggleButton)findViewById(R.id.tbLock);
tbLock.setOnClickListener(this);
tbScroll = (ToggleButton)findViewById(R.id.tbScroll);
tbScroll.setOnClickListener(this);
tbStream = (ToggleButton)findViewById(R.id.tbStream);
tbStream.setOnClickListener(this);
//init toggleButton
Lock=true;
AutoScrollX=true;
Stream=true;
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(broadcastReceiver, filter);
init();
}
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_USB_PERMISSION)) {
boolean granted =
intent.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED);
if (granted) {
connection = usbManager.openDevice(device);
serialPort = UsbSerialDevice.createUsbSerialDevice(device, connection);
if (serialPort != null) {
if (serialPort.open()) { //Set Serial Connection Parameters.
//setUiEnabled(true); //Enable Buttons in UI
serialPort.setBaudRate(57600);
serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
serialPort.setParity(UsbSerialInterface.PARITY_NONE);
serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
serialPort.read(mCallback); //
//connectionstatus.setText("Connected");
tvAppend(connectionstatus, " Opened!\n");
} else {
Log.d("SERIAL", "PORT NOT OPEN");
}
} else {
Log.d("SERIAL", "PORT IS NULL");
}
} else {
Log.d("SERIAL", "PERM NOT GRANTED");
}
} else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
onConnect(bConnect);
} else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
// onClickStop(buttonRestart);
}
}
};
public void onConnect(View view){
HashMap<String, UsbDevice> usbDevices = usbManager.getDeviceList();
if (!usbDevices.isEmpty()) {
boolean keep = true;
for (Map.Entry<String, UsbDevice> entry : usbDevices.entrySet()) {
device = entry.getValue();
int deviceVID = device.getVendorId();
if (deviceVID == 0x10C4)//Arduino Vendor ID//0x10C4 cp2102 VID
{
PendingIntent pi = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
usbManager.requestPermission(device, pi);
keep = false;
} else {
connection = null;
device = null;
}
if (!keep)
break;
}
}
}
private void tvAppend (TextView tv, CharSequence text){
connectionstatus.setText(" ");
final TextView ftv = tv;
final CharSequence ftext = text;
runOnUiThread(new Runnable() {
@Override
public void run() {
ftv.append(ftext);
}
});
}
void init(){
//Bluetooth.gethandler(mHandler);
//init graphview
GraphView = (LinearLayout) findViewById(R.id.Graph);
// init example series data-------------------
Series = new GraphViewSeries("Signal",
new GraphViewStyle(Color.YELLOW, 2),//color and thickness of the line
new GraphViewData[] {new GraphViewData(0, 0)});
graphView = new LineGraphView(
this // context
, "Electrocardiogram AUTH" // heading
);
graphView.setViewPort(0, Xview);
graphView.setScrollable(true);
graphView.setScalable(false);
graphView.setShowLegend(false);
//graphView.setLegendAlign(LegendAlign.BOTTOM);
graphView.setManualYAxis(true);
graphView.setManualYAxisBounds(2560, 0);
graphView.addSeries(Series); // data
GraphView.addView(graphView);
}
Handler mHandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case MESSAGE_FROM_SERIAL_PORT:
plotdata = data;
g_intRawBuffer[block][TotalSample] = plotdata;
TotalSample = TotalSample+1;
if (TotalSample == 8) {
TotalSample = 0;
for (int sample = 0; sample <= (gMAX_SAMPLES - 1); sample++) {
g_sngDnOutBuf[sample] = g_intRawBuffer[block][sample];
}
for (int sample = 0; sample <= (gMAX_SAMPLES - 1); sample++) {
Series.appendData(new GraphViewData(graph2LastXValue, g_sngDnOutBuf[sample]), AutoScrollX);
if (graph2LastXValue >= Xview && Lock == true) {
Series.resetData(new GraphViewData[]{});
graph2LastXValue = 0;
}else
graph2LastXValue += 0.5;
if (Lock == true)
graphView.setViewPort(0, Xview);
else
graphView.setViewPort(graph2LastXValue - Xview, Xview);
//refresh
GraphView.removeView(graphView);
GraphView.addView(graphView);
}
}
}
}
};
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId()){
case R.id.bConnect:
HashMap<String, UsbDevice> usbDevices = usbManager.getDeviceList();
if (!usbDevices.isEmpty()) {
boolean keep = true;
for (Map.Entry<String, UsbDevice> entry : usbDevices.entrySet()) {
device = entry.getValue();
int deviceVID = device.getVendorId();
if (deviceVID == 0x2341)//Arduino Vendor 2341 ID//0x10C4 cp2102 VID
{
PendingIntent pi = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
usbManager.requestPermission(device, pi);
keep = false;
} else {
connection = null;
device = null;
}
if (!keep)
break;
}
}
break;
case R.id.bDisconnect:
serialPort.close();
tvAppend(connectionstatus, "Serial Connection Closed!\n");
break;
case R.id.bXminus:
if (Xview<30) Xview++;
break;
case R.id.bXplus:
if (Xview>1) Xview--;
break;
case R.id.tbLock:
if (tbLock.isChecked()){
Lock = true;
}else{
Lock = false;
}
break;
case R.id.tbScroll:
if (tbScroll.isChecked()){
AutoScrollX = true;
}else{
AutoScrollX = false;
}
break;
case R.id.tbStream:
if (tbStream.isChecked()){
serialPort.write("a".getBytes());
}else{
serialPort.write("z".getBytes());
control_a = 0;
}
break;
}
}
}
解决方案
推荐阅读
- javascript - 基于Typescript中的参数调用不同的数组
- java - linux中的类路径读取未按预期工作
- xamarin - 有没有办法解决 SwipeListener 和同一视图上的触摸输入之间的冲突?
- c# - MongoDB Atlas 插入很多很慢
- logging - 尝试提取 GNU Octave 软件的提交日志
- javascript - 如何在 IE11 上更改 YandexMaps 上按钮的类名?
- ssl - 使用 TLS 验证 MQTT 代理时出现问题
- python - 如何在网页上训练我自己的自定义词嵌入?
- go - 所有的 goroutine 都在休眠 - 死锁!与等待组
- excel - 如何选择文件并将文件路径粘贴到嵌入的文本框中?