在扫码枪连接机器的时候,当扫码枪扫描到内容时,获取扫描到的内容。
之前扫码枪使用的是USB模式(即扫描到的内容会直接输入到EditText之中,并且末尾会增加一个回车键),但是后来发现,当二维码包含中文的时候,中文不会输出进来,于是乎,使用以上两种方式实现。
连接扫码枪,因为数据肯定是以字节流的方式发送的,那么我们只需获取到输入的字节流,自己处理成需要的内容就可以了。
需要经过以下几个步骤:
步骤一:集成谷歌原生serial_port包,这个自己看上面教程了。
步骤二:寻找设备串口地址,在完成步骤一之后,会有一个SerialPortFinder的类,这个类的作用是寻找咱们安卓设备上连接的串口设备(包括扫码枪),具体获取扫码枪串口地址的思路:获取未插入扫码枪时所有设备的串口地址------》获取插入扫码枪时所有设备的串口地址
-----》看看多出那个,多出的那个就是扫码枪的串口地址了,废话不多说,直接贴代码了:
case R.id.btn_print://获取所有串口设备地址,mFinder就是SerialPortFinder
StringBuffer stringBuffer = new StringBuffer();
for (String str:mFinder.getAllDevicesPath()) {
stringBuffer.append(str + "\n");
}
mTvMessage.setText(stringBuffer.toString());
break;
怎么找USB扫码枪你懂我意思吧。
步骤三:连接设备:
废不多讲,首先咱们连接到串口设备,如果你连接不上,那么就是步骤一有问题,请到步骤一那篇博客问问作者:
private String mSerialPath = "/dev/ttyUSB0" ;//物理串口地址,这个就是咱们步骤二找到的地址了,这是我的设备的地址,你的自己找去
private int baudrate = 9600;//波特率,这个是可以扫码枪自己设置的,看说明书
private SerialPort mSerialPort;
private InputStream mInputStream;
@Override
protected int getContentView() {
return R.layout.activity_test;
}
@Override
protected void initView() {
super.initView();
initSerialPort();
}
private void initSerialPort(){//连接串口设备,建议加try,硬件设备你永远不知道会为啥崩溃
try {
mSerialPort = new SerialPort(new File(mSerialPath),baudrate);
mInputStream = mSerialPort.getInputStream();
ReadThread thread = new ReadThread();//这是读取数据流的线程,代码在下方贴出
thread.start();//启动数据流读取线程
} catch (Exception e) {
e.printStackTrace();
}
}
步骤四:获取数据流,这时候步骤三,我们开启了一个线程读取扫码枪的数据流,这时候我写了一个死循环,轮询扫码枪发送的内容,线程代码如下
private InputStream mInputStream;
/**
* 读串口线程
*/
private class ReadThread extends Thread {//这是我的内部类,我代码习惯不好,别瞎鸡儿抄
@Override
public void run() {
super.run();
while ((!Thread.currentThread().isInterrupted())) {
final int size;
try {
if (mInputStream == null)
return;
final byte[] buffer = new byte[512];
size = mInputStream.read(buffer);//这就是扫描到的内容了
if (size > 0) {
runOnUiThread(new Runnable() {
@Override
public void run() {
try {
ToastUtils.makeText(TestActivity.this,new String(buffer,"GB2312"));//此处我设置的编码是GB2312,这个可以看说明书,可以设置的
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
});
}
Thread.sleep(300);//你自己可以设置睡眠时间,这个睡眠时间可以会影响识别速度,那么就可以叫用户加钱,你懂我意思吧。
} catch (Exception e) {
//如果抛出异常则再次设置中断请求
Thread.currentThread().interrupt();
return;
}
}
}
}
嗯,到了这一步,大功告成了。
注意:串口方式实现的话兼容性不好,因为遇到部分安卓设备直接阉割了这部分功能,所以我才会研究USB方式的。
该种方式好处在于不需要集成serial_port包,但是里面一些类理解比较灵性,USB方式需要经过以下几个步骤:
步骤一:寻找需要连接的devices设备,这里的话有两种场景
1.USB扫码枪一直插在安卓设备上,我们需要在程序启动的时候自动找到并且连接
2.USB扫码枪在热拔插的情况下,我们需要在插入的时候连接
第一种的话我是直接写了一个方法,在程序启动的时候检查时候插入需要支持的设备类型,如果有,那么直接连接,判断方法是通过设备的pid和vid对比进行判断,pid和vid获取方式自己百度,或者把扫码枪插在电脑上,在设备管理可以看到,我通过findDevices方法找到需要连接的扫码枪设备。
贴代码:
private UsbManager mManager;
//查找已连接的设备
UsbDevice findDevices() {
if (null == mManager) {
return null;
}
HashMap mMap = mManager.getDeviceList();
for (UsbDevice device : mMap.values()) {
if (BaseScanner.isS5920(device) || BaseScanner.isS5600(device)) {//判断设备是否支持的类型
return device;
}
}
return null;
}
这是baseScanner,这个类名我觉得不够准确,它是用来记录需要支持的设备的信息的,包含设备的判断方法:
public class BaseScanner{
private static final int scanner5600_pid = 4456;
private static final int scanner5600_vid = 866;
private static final int scanner5920_pid = 9527;
private static final int scanner5920_vid = 549;
public static boolean isS5600(UsbDevice usbDevice){//是不是s5600扫码枪
return usbDevice.getProductId() == scanner5600_pid && usbDevice.getVendorId() == scanner5600_vid;
}
public static boolean isS5920(UsbDevice usbDevice){//是不是s5920
return usbDevice.getProductId() == scanner5920_pid && usbDevice.getVendorId() == scanner5920_vid;
}
}
第二种USB扫码枪热拔插连接方式,这时候我们采用的是广播监听的方式,因为设备拨叉都会有广播发送,这条广播包含的信息包含一个USBDevices对象(也就是扫码枪),我们需要动态注册拔,插两条广播,静态注册不生效,代码如下:
//这是广播类,因为我的扫描是写在一个service中,所以把连接的设备交给service处理就可以
public class USBBroadcastReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String action = intent.getAction();
if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null) {
// call your method that cleans up and closes communication with the device
Toast.makeText(context, "拔出", Toast.LENGTH_LONG).show();
}
}else if(UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)){//设备插入
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);//获取插入的设备
Intent intent1 = new Intent(context,ScannerService.class);
Bundle bundle = new Bundle();
bundle.putParcelable("device",device);
intent1.putExtra("data",bundle);//将设备包入intent中,交给service处理
context.startService(intent1);
Toast.makeText(context, "插入", Toast.LENGTH_LONG).show();
}
}
}
我是在程序启动的时候就注册了这个广播如下:
public class MyApplication extends Application {
private USBBroadcastReceiver mUsbReceiver;
@Override
public void onCreate() {
super.onCreate();
registBroadCast();
}
@Override
public void onTerminate() {
unregisterReceiver(mUsbReceiver);
super.onTerminate();
}
private void registBroadCast(){//注册USB插拔广播
mUsbReceiver = new USBBroadcastReceiver();
IntentFilter usbDeviceStateFilter = new IntentFilter();
usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);//插入设备状态
usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);//拔出设备状态
registerReceiver(mUsbReceiver, usbDeviceStateFilter);
}
}
步骤二,连接设备,这边我把所有都写注释里面:
private UsbDevice mDevide;
private UsbDeviceConnection mConnect;
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
private static UsbConnectManager mInstance;
private ScannerListener mListener;
private UsbManager mManager;
private UsbEndpoint mUsbEndpointIn;
private UsbInterface mUsbInterface;
private Thread mReadingthread;
public void connetDevice(UsbDevice device, Context context) {
disConnect();//断开之前的连接
mDevide = device;//当前需要连接的设备
try {
if (!mManager.hasPermission(mDevide)) {//检查是否有扫码枪的访问权限,如果没有,那么请求一下临时权限
PendingIntent intent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
mManager.requestPermission(mDevide, intent);
}
mConnect = mManager.openDevice(mDevide);//打开设备
mUsbInterface = device.getInterface(0);//获取数据的接口.这个可以理解成设备有多少个线头子
mUsbEndpointIn = mUsbInterface.getEndpoint(0);//获取设备的输出流向,输入或者输出因为usb扫码枪只有一个输出项,所以直接选择0
if (mConnect.claimInterface(mUsbInterface, true)) {//获取设备数据写入流,如果获取成功,那么数据已经通常,我这边写的是一个获取数据,输入数据的话把getEndpoint(0)换成输入的接口即可
Log.i(TAG, "connetDevice: find device,start get data!!!");
startReading();//开启读取数据流的线程
} else {
mConnect.close();
Log.i(TAG, "connetDevice: not find device !!!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
步骤三,获取输入的流,并解析成需要的内容,代码如下:
//开线程读取数据
private void startReading() {
if (null != mReadingthread) {
mReadingthread.interrupt();
}
mReadingthread = new Thread(new Runnable() {
@Override
public void run() {
while (!mReadingthread.isInterrupted()) {
synchronized (this) {
byte[] bytes = new byte[128];
int ret = mConnect.bulkTransfer(mUsbEndpointIn, bytes, bytes.length, 100);//获取数据流
if (ret > 0) {
try {
byte[] bs = new byte[ret];
System.arraycopy(bytes, 0, bs, 0, ret);//获取数据长度
String str = new String(bs,"GB2312");//转换成汉字
if (null != mListener){
mListener.onScanner(str);//你自己需要的处理方式
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
}
});
mReadingthread.start();
}
OK啦,USB模式的也完成了。
有疑问或者有建议的膀友可以加群:497438697 我是群里的 杭州-大魔王,有艾特必应。
祝大家新年快乐,万事亨通!!!