近期公司项目有个Android大屏上的应用开发,外设用到rfid读卡器(usb或者uart接口),为了对外接口简单使用usb和外置读卡器连接。
驱动移植本着拿来主义直接参考了GitHub上UsbSerial的开源代码,仔细阅读代码发现大神使用的Service来实现,梳理自己应用需求:1、读卡器挂载后自动设置功率;2、多个界面和读卡器进行读写数据交互。受限Android挂载usb设备请求弹窗不好处理,要求usb service不可以在切换界面时stop。按照service的两种通用启动方式来看都不是很好处理。
这里贴一下service的通用启动方式(复习记录):
方式1:startService(new Intent(this, UsbService.class));
方式2:mContext.bindService(new Intent(mContext,UsbService.class),usbConnection,Context.BIND_AUTO_CREATE);
两种启动方式区别不做详细阐述,可自行查阅资料(本人纯小白)。大致区别:方式1启动service,service生命周期和调用startService函数的Activity没关系,但是方式1启动service和activity交互就不好搞、方式2启动service,service的生命周期和当前activity周期一致(切记bindService和unbindService成对),方式2启动可以通过上诉参数usbConnection获取service实体实现和activity的数据交互。
梳理到这里就发现和我自己的需求相悖,我要求usb service在后台运行,同时切换界面后可以和usb service实现数据读写交互,如果每次切换界面调用unbindService,service停止后,在新的activity中调用bindService启动service,势必需要会出现新的usb确认弹窗,用户体验很差。
继续查阅资料,发现service的两种启动方式可以结合使用。结合自己的需求,app启动后首界面直接通过调用方法1启动usb service,在需要和usb service交互的activity的界面可以继续调用方法2来实现usb service的数据交互,这里切记不要忘了unbindService,但是调用unBindService不会干掉service,即可实现我的应用需求。
继续优化发现,用着还是有点麻烦,每次bind、unbind大量冗余代码,我又将这块代码封装成一个工具类。
public class RfidTool implements HandlerAction, UsbService.OnUsbResponseListener {
// 上下文
private Context mContext;
// service
protected UsbService mUsbService;
//读卡状态标志 false:默认状态 true:读卡过程中
protected boolean mReadCardFlag =false;
//service和activity连接时间
private int mBindServiceTime =200;
//service和activity是否已经连接上
protected boolean serviceIsBinded =false;
//activiy用的回调接口
private RfidToolCallback mRfidToolCallback;
//超时时间
private int mTimeout =0;
//指令
private List<Byte> mCmd =new ArrayList<>();
public RfidTool(Context mContext) {
this.mContext = mContext;
}
public Context getContext() {
return mContext;
}
public void setmCmd(List mCmd) {
this.mCmd = mCmd;
}
//绑定
public RfidTool bindService() {
if (!UsbService.SERVICE_CONNECTED) {
Timber.d("start service");
mContext.startService(new Intent(mContext,PhotoUpdateSerivice.class));
}
Intent intent =new Intent(mContext,UsbService.class);
mContext.bindService(intent,usbConnection,Context.BIND_AUTO_CREATE);
return this;
}
//connection
private final ServiceConnection usbConnection =new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName arg0,IBinder arg1) {
serviceIsBinded =true;
mUsbService = ((UsbService.UsbBinder) arg1).getService();
mUsbService.setUsbResponseListener(RfidTool.this);
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mUsbService =null;
}
};
//开始
public void start(RfidToolCallback callback){
mReadCardFlag =true;
this.mRfidToolCallback = callback;
if(mRfidToolCallback !=null){
mRfidToolCallback.onStart();
}
//service和activity bind成功需要一定时间
postDelayed(()->{
if (mUsbService ==null) {
failed("USB服务未打开");
return;
}
if(!mUsbService.isSerialPortConnected()){
mUsbService.findSerialPortDevice();
failed("未找到读卡器");
return;
}
mUsbService.write(ArrayUtil.listToByte(mCmd));
} ,mBindServiceTime);
}
//操作失败(解除绑定、移除回调)
protected void failed(String message){
mUsbService.setUsbResponseListener(null);
removeCallbacks();
if(serviceIsBinded){
serviceIsBinded =false;
mContext.unbindService(usbConnection);
}
if(mRfidToolCallback !=null){
mRfidToolCallback.onFailed(message);
mRfidToolCallback.onEnd();
}
}
//操作成功
protected void succeed(){
mUsbService.setUsbResponseListener(null);
getContext().unbindService(usbConnection);
removeCallbacks();
if(mRfidToolCallback !=null){
mRfidToolCallback.onSuccess();
mRfidToolCallback.onEnd();
}
}
@Override
public void onDataReceived(byte[] data) {
}
}