因为要写串口功能检测串口是否正常,也是参考了网上很多博客和例程,从中取出自己需要的,舍弃不需要的,再加以优化,就是这么个过程了.
这是我的串口功能的目录结构:
实际上把jni和libs文件夹建好,导入网上下载的相关文件,然后把SerialPort.java和SerialPortFinder.java放入android_serialport_api包下(要注意这两个类必须放入这个包下,听说和libs中的动态链接库有关系,反正你就放到这个包里面就行了,不用多想).
先创建一个SerialPortActivity,源码如下:
public abstract class SerialPortActivity extends Activity {
protected SerialPort mSerialPort;
protected OutputStream mOutputStream;
private InputStream mInputStream;
private ReadThread mReadThread;
private class ReadThread extends Thread {
@Override
public void run() {
super.run();
while (!isInterrupted()) {
int size;
try {
byte[] buffer = new byte[64];
if (mInputStream == null) {
return;
}
size = mInputStream.read(buffer);
if (size > 0) {
onDataReceived(buffer, size);
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
}
private void DisplayError(int resourceId) {
AlertDialog.Builder b = new AlertDialog.Builder(this);
b.setTitle("Error");
b.setMessage(resourceId);
b.setPositiveButton("OK", new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//SerialPortActivity.this.finish();
}
});
b.show();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public boolean OpenSerialPort(String path, int baudrate) {
try {
mSerialPort = getSerialPort(path, baudrate);
mOutputStream = mSerialPort.getOutputStream();
mInputStream = mSerialPort.getInputStream();
/* Create a receiving thread 创建一个接受数据的线程 */
mReadThread = new ReadThread();
mReadThread.start();
} catch (SecurityException e) {
DisplayError(R.string.error_security);
return false;
} catch (IOException e) {
DisplayError(R.string.error_unknown);
return false;
} catch (InvalidParameterException e) {
DisplayError(R.string.error_configuration);
return false;
}
return true;
}
public SerialPort getSerialPort(String path, int baudrate) throws SecurityException, IOException, InvalidParameterException {
if (mSerialPort == null) {
/* Check parameters */
if ((path.length() == 0) || (baudrate == -1)) {
throw new InvalidParameterException();
}
/* Open the serial port */
// mSerialPort = new SerialPort(new File("/dev/ttySAC1"), 9600, 0);
mSerialPort = new SerialPort(new File(path), baudrate, 0);
}
return mSerialPort;
}
protected abstract void onDataReceived(final byte[] buffer, final int size);
@Override
protected void onDestroy() {
if (mReadThread != null)
mReadThread.interrupt();
if (mSerialPort != null) {
mSerialPort.close();
mSerialPort = null;
}
super.onDestroy();
}
}
在这个Activity里面打开串口,创建ReadThread读取数据,还有提示串口的各种错误信息.
再创建一个活动ConsoleActivity继承自SerialPortActivity,源码如下:
public class ConsoleActivity extends SerialPortActivity {
private TextView serialNumTxt,baudrateTxt;
private EditText mReception;
private EditText Emission;
private TextView stateTxt;
static String serialDevPath = "/dev/ttyS0";//待测试串口路径
String str;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.console);
//初始化控件
initView();
boolean flag = ConsoleActivity.super.OpenSerialPort(serialDevPath, 9600);
//发送数据
if (!flag) {
stateTxt.setText(R.string.falseState);
stateTxt.setTextColor(Color.RED);
return;
}
stateTxt.setText(R.string.trueState);
stateTxt.setTextColor(Color.GREEN);
CharSequence t = Emission.getText();
char[] text = new char[t.length()];
for (int i = 0; i < t.length(); i++) {
text[i] = t.charAt(i);
}
try {
mOutputStream.write(new String(text).getBytes());
//mOutputStream.write(' ');
} catch (IOException e) {
e.printStackTrace();
}
}
private void initView() {
// TODO Auto-generated method stub
mReception = (EditText) findViewById(R.id.EditTextReception);
mReception.setEnabled(false);
mReception.setFocusable(false);
mReception.setTextColor(Color.WHITE);
Emission = (EditText) findViewById(R.id.EditTextEmission);
Emission.setEnabled(false);
Emission.setFocusable(false);
Emission.setText("Hello,World!");
stateTxt=(TextView)findViewById(R.id.stateTxt);
serialNumTxt = (TextView)findViewById(R.id.serialportNum);
serialNumTxt.setText(this.getResources().getString(R.string.serialName)+serialDevPath);
baudrateTxt = (TextView)findViewById(R.id.baundrate);
baudrateTxt.setText(this.getResources().getString(R.string.baundrate)+"9600");
}
@Override
protected void onDataReceived(final byte[] buffer, final int size) {
runOnUiThread(new Runnable() {
public void run() {
// if (mReception != null) {
mReception.append(new String(buffer, 0, size));
//mReception.append(" ");
// }
}
});
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
// 创建退出对话框
AlertDialog.Builder isExit = new Builder(this);
// 设置对话框标题
isExit.setTitle("BRIGHTNESS Test");
// 设置对话框消息
isExit.setMessage("测试通过");
// 添加选择按钮并注册监听
isExit.setPositiveButton("同意", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
str = "yes";
Uri data = Uri.parse(str);
Intent result = new Intent(null, data);
setResult(RESULT_OK, result);
finish();
}
});
isExit.setNegativeButton("否定", new android.content.DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
str = "no";
Uri data = Uri.parse(str);
Intent result = new Intent(null, data);
setResult(RESULT_OK, result);
finish();
}
});
// 对话框显示
isExit.create().show();
}
return false;
}
}
这里我是固定设置的串口号,你可以通过SerialPortFinder类的getAllDevices方法找到所有的串口号,然后加到一个Spinner中,再设置OnItemSelectedLisener就可以实现选择串口号的功能.
布局文件源码如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal" >
<TextView
android:id="@+id/serialportNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
android:gravity="center_horizontal"
android:text="@string/serialName"
android:textSize="@dimen/serialSize" />
<TextView
android:id="@+id/baundrate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/serialportNum"
android:layout_marginTop="10dp"
android:layout_alignLeft="@id/serialportNum"
android:text="@string/baundrate"
android:textSize="@dimen/serialSize" />
<TextView
android:id="@+id/sendArea"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/baundrate"
android:layout_marginTop="10dp"
android:layout_alignLeft="@id/serialportNum"
android:text="@string/send"
android:textSize="@dimen/serialSize" />
<EditText
android:id="@+id/EditTextEmission"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/sendArea"
android:layout_alignBottom="@id/sendArea"
android:layout_weight="1" />
<TextView
android:id="@+id/recArea"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/sendArea"
android:layout_marginTop="10dp"
android:layout_alignLeft="@id/sendArea"
android:text="@string/rec"
android:textSize="@dimen/serialSize" />
<EditText
android:id="@+id/EditTextReception"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/recArea"
android:layout_alignBottom="@id/recArea"
android:layout_weight="1" />
<TextView android:id="@+id/serialState"
android:layout_below="@id/recArea"
android:layout_alignLeft="@id/serialportNum"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/serialState"
android:textSize="@dimen/serialSize"
android:textAlignment="viewStart" />
<TextView android:id="@+id/stateTxt"
android:layout_toRightOf="@id/serialState"
android:layout_alignBottom="@id/serialState"
android:layout_alignLeft="@id/EditTextReception"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textSize="@dimen/serialSize" />
</RelativeLayout>
最后实现的界面如下:
网上例程很多,我之前是已经把网上的一个例程给调通了,但是想把这个串口功能作为一个子活动加入我的项目中,却是各种崩溃,原因也找不到,现在能OK也是经历一番摸索,不容易.网上的例程有的是通过Application来把找到的串口号列表加入全局变量,有的是sharedpreferrce保存设置过的参数,这些我都没要,做到了简化的极限了.
在网上看到说在6.0以上版本运行会报错,但是我没有发现这情况,只是使用外部库总是会弹窗提示text location,这个问题还不知道怎么解决.
想把这个功能加入某个项目中作为子活动的话只要在主活动中通过Intent跳到ConsoleActivity中就可以了,很方便.
调试用的设备不知道什么原因没有LOG打印,只能在代码中通过注释某一部分来确定问题所在.
2018年3月28日 16:38:29
现在此功能已经完全OK了,解决弹窗请看解决串口弹窗
2018年4月24日 20:23:17
相比大的项目,各种独立的小Demo才应该是我们要保留的对象,我对此感受颇深.
又有Android串口相关的项目,我从大项目中将串口测试模块单独拿出来,却莫名其妙崩溃,一整天弄的我心态都要炸了,终于在此时此刻,运行OK,没有崩溃的情况了,在此把Demo分享出来,免得下次又有意外.