【背景】
折腾:
【已解决】Android设备作为Host希望实现可以检测到USB设备插入
期间,需要尝试去通过,新建一个线程或进程,然后去动态检测USB设备的插入。
【折腾过程】
1.先去搞懂,android中如何新建线程。
2.官网文档:
https://developer.android.com/reference/java/lang/Thread.html
3.看看:
Android create new thread in service class
去试试。
4.期间出现:
【已解决】android中switch中的case中不用使用enum枚举值:Type mismatch: cannot convert from xxx to int
5.再去继续写代码测试。
然后又遇到:
6.然后用了代码:
usbActionDetectThread =new Thread( new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), "Begin check usb action", 1000).show(); UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); HashMap<String, UsbDevice> deviceList = manager.getDeviceList(); Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); while(deviceIterator.hasNext()){ UsbDevice device = deviceIterator.next(); int usbVid = device.getVendorId(); int usbPid = device.getProductId(); if((usbVid == ft232rUartVid) && (usbPid ==ft232rUartPid) ){ Toast.makeText(getApplicationContext(), "Found Usb device: FT232R UART", Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(), "Now send message USB_ACTION_ATTACH to activity ", Toast.LENGTH_LONG).show(); Message foundUsbDeviceAttachMsg =new Message(); foundUsbDeviceAttachMsg.what=usb_action.USB_ACTION_ATTACH.getAction(); mHandler.sendMessage(foundUsbDeviceAttachMsg); break; } else { Toast.makeText(getApplicationContext(), "Found USB VID="+usbVid+" PID=" + usbPid, Toast.LENGTH_LONG).show(); } } try { Thread.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block //e.printStackTrace(); } } }); usbActionDetectThread.start();
结果都没指定到:
run函数里面去。。。
7.参考:
How to Send the Current Thread to Sleep
去改为:
usbActionDetectThread =new Thread() //new Runnable() { { // @Override public void run() { Toast.makeText(getApplicationContext(), "Begin check usb action", 1000).show(); UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); HashMap<String, UsbDevice> deviceList = manager.getDeviceList(); Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); while(deviceIterator.hasNext()){ UsbDevice device = deviceIterator.next(); int usbVid = device.getVendorId(); int usbPid = device.getProductId(); if((usbVid == ft232rUartVid) && (usbPid ==ft232rUartPid) ){ Toast.makeText(getApplicationContext(), "Found Usb device: FT232R UART", Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(), "Now send message USB_ACTION_ATTACH to activity ", Toast.LENGTH_LONG).show(); Message foundUsbDeviceAttachMsg =new Message(); foundUsbDeviceAttachMsg.what=usb_action.USB_ACTION_ATTACH.getAction(); mHandler.sendMessage(foundUsbDeviceAttachMsg); break; } else { Toast.makeText(getApplicationContext(), "Found USB VID="+usbVid+" PID=" + usbPid, Toast.LENGTH_LONG).show(); } } try { Thread.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block //e.printStackTrace(); } } }; usbActionDetectThread.start();
再去试试是否能运行到。
结果还是不行。
8.再改为通过Handler:
//public class DeviceListActivity extends BaseActivity { public class DeviceListActivity extends BaseActivity implements Runnable { @Override public void run() { //0x0403 / 0x6001: FTDI FT232R UART final int ft232rUartVid = 0x0403; //1027 final int ft232rUartPid = 0x6001; //24577 Toast.makeText(getApplicationContext(), "Begin check usb action", 1000).show(); UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); HashMap<String, UsbDevice> deviceList = manager.getDeviceList(); Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); while(deviceIterator.hasNext()){ UsbDevice device = deviceIterator.next(); int usbVid = device.getVendorId(); int usbPid = device.getProductId(); if((usbVid == ft232rUartVid) && (usbPid ==ft232rUartPid) ){ Toast.makeText(getApplicationContext(), "Found Usb device: FT232R UART", Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(), "Now send message USB_ACTION_ATTACH to activity ", Toast.LENGTH_LONG).show(); Message foundUsbDeviceAttachMsg =new Message(); foundUsbDeviceAttachMsg.what=usb_action.USB_ACTION_ATTACH.getAction(); mHandler.sendMessage(foundUsbDeviceAttachMsg); break; } else { Toast.makeText(getApplicationContext(), "Found USB VID="+usbVid+" PID=" + usbPid, Toast.LENGTH_LONG).show(); } } } private void usbActionDetectViaHandler(){ mHandler=new Handler() { public void handleMessage(Message msg) { usb_action curUsbAction = usb_action.values()[msg.what]; //do your own bounds checking switch(curUsbAction) { case USB_ACTION_UNKNOWN: Toast.makeText(getApplicationContext(), "Unkown USB action !", Toast.LENGTH_LONG).show(); break; case USB_ACTION_ATTACH: //TODO: do auto scan hart devices Toast.makeText(getApplicationContext(), "Now should call the HART auto scan", Toast.LENGTH_LONG).show(); break; case USB_ACTION_DETACH: //stop auto detect usb action thread Toast.makeText(getApplicationContext(), "Now destory the usb action detect thread", Toast.LENGTH_LONG).show(); usbActionDetectThread.destroy(); break; default: break; } super.handleMessage(msg); } }; Thread curThread=new Thread(this); curThread.start(); }
结果却会出错:
参考:
[Java:Eclipse]JDI thread evaluations:Exception processing async thread queue
去关闭Expressions视图,
重新debug,看看是否还会有该错误。
果然没了该错误了。
但是该运行的代码,还是没运行到。。。
9.参考:
Specifying the Code to Run on a Thread
看到其中关键一句:
Remember, though, that the Runnable won’t be running on the UI thread, |
所以,上述的代码,写在Runnable中的,是没法运行在:
我当前的,本身就是出于UI线程中的。
但是应该是:
的确底层,去新建了线程,去执行对应的代码的。
10.后来发现,上述代码出错了:
11-06 16:47:42.988: E/AndroidRuntime(3037): FATAL EXCEPTION: Thread-361 11-06 16:47:42.988: E/AndroidRuntime(3037): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() 11-06 16:47:42.988: E/AndroidRuntime(3037): at android.os.Handler.<init>(Handler.java:121) 11-06 16:47:42.988: E/AndroidRuntime(3037): at android.widget.Toast$TN.<init>(Toast.java:347) 11-06 16:47:42.988: E/AndroidRuntime(3037): at android.widget.Toast.<init>(Toast.java:93) 11-06 16:47:42.988: E/AndroidRuntime(3037): at android.widget.Toast.makeText(Toast.java:240) 11-06 16:47:42.988: E/AndroidRuntime(3037): at com.yy.xxx.activities.DeviceListActivity.run(DeviceListActivity.java:298) 11-06 16:47:42.988: E/AndroidRuntime(3037): at java.lang.Thread.run(Thread.java:856) 11-06 16:47:43.386: D/dalvikvm(3037): threadid=1: still suspended after undo (sc=1 dc=1)
看代码中的:
public void run() {
很明显是:
第一句就是:
298行的:
Toast.makeText(getApplicationContext(), "Begin check usb action", 1000).show();
结果导致了上面的
at com.yy.xxx.activities.DeviceListActivity.run(DeviceListActivity.java:298)
调用makeText出错:
at android.widget.Toast.makeText(Toast.java:240)
的。
11.所以,去参考:
Communicating with the UI Thread
看看如何打印toast。
算了,暂时不打印toast了,改为log算了:
@Override public void run() { //0x0403 / 0x6001: FTDI FT232R UART final int ft232rUartVid = 0x0403; //1027 final int ft232rUartPid = 0x6001; //24577 //Toast.makeText(getApplicationContext(), "Begin check usb action", 1000).show(); gLogger.debug("Begin check usb action"); UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); HashMap<String, UsbDevice> deviceList = manager.getDeviceList(); Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); while(deviceIterator.hasNext()){ UsbDevice device = deviceIterator.next(); int usbVid = device.getVendorId(); int usbPid = device.getProductId(); if((usbVid == ft232rUartVid) && (usbPid ==ft232rUartPid) ){ //Toast.makeText(getApplicationContext(), "Found Usb device: FT232R UART", Toast.LENGTH_LONG).show(); //Toast.makeText(getApplicationContext(), "Now send message USB_ACTION_ATTACH to activity ", Toast.LENGTH_LONG).show(); gLogger.debug("Found Usb device: FT232R UART"); gLogger.debug("Now send message USB_ACTION_ATTACH to activit"); Message foundUsbDeviceAttachMsg =new Message(); foundUsbDeviceAttachMsg.what=usb_action.USB_ACTION_ATTACH.getAction(); mHandler.sendMessage(foundUsbDeviceAttachMsg); break; } else { //Toast.makeText(getApplicationContext(), "Found USB VID="+usbVid+" PID=" + usbPid, Toast.LENGTH_LONG).show(); gLogger.debug("Found USB VID="+usbVid+" PID=" + usbPid); } } }
然后继续调试。
然后的确可以运行到这个run函数了。
12.但是又有问题:
代码:
@Override public void run() { //0x0403 / 0x6001: FTDI FT232R UART final int ft232rUartVid = 0x0403; //1027 final int ft232rUartPid = 0x6001; //24577 //Toast.makeText(getApplicationContext(), "Begin check usb action", 1000).show(); gLogger.debug("Begin check usb action"); UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); HashMap<String, UsbDevice> deviceList = manager.getDeviceList(); Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); while(deviceIterator.hasNext()){ UsbDevice device = deviceIterator.next(); int usbVid = device.getVendorId(); int usbPid = device.getProductId(); if((usbVid == ft232rUartVid) && (usbPid ==ft232rUartPid) ){ //Toast.makeText(getApplicationContext(), "Found Usb device: FT232R UART", Toast.LENGTH_LONG).show(); //Toast.makeText(getApplicationContext(), "Now send message USB_ACTION_ATTACH to activity ", Toast.LENGTH_LONG).show(); gLogger.debug("Found Usb device: FT232R UART"); gLogger.debug("Now send message USB_ACTION_ATTACH to activit"); Message foundUsbDeviceAttachMsg =new Message(); foundUsbDeviceAttachMsg.what=usb_action.USB_ACTION_ATTACH.getAction(); mHandler.sendMessage(foundUsbDeviceAttachMsg); break; } else { //Toast.makeText(getApplicationContext(), "Found USB VID="+usbVid+" PID=" + usbPid, Toast.LENGTH_LONG).show(); gLogger.debug("Found USB VID="+usbVid+" PID=" + usbPid); } } try { Thread.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
只运行了一次,只执行了一次的sleep的200毫秒后,结果就不再执行了。
所以需要去解决:
【已解决】为何android中实现了Runnable的进程只运行了一次
然后就可以正常检测usb的状态了。
【总结】
此处,相关代码为:
public class DeviceListActivity extends BaseActivity implements Runnable { private Thread usbActionDetectThread = null; public Handler mHandler; @Override public void run() { // set to lower priority android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND); //0x0403 / 0x6001: FTDI FT232R UART final int ft232rUartVid = 0x0403; //1027 final int ft232rUartPid = 0x6001; //24577 boolean bNotFoundUsb = true; while(bNotFoundUsb) { //Toast.makeText(getApplicationContext(), "Begin check usb action", 1000).show(); gLogger.debug("Begin check usb action"); UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); HashMap<String, UsbDevice> deviceList = manager.getDeviceList(); Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); while(deviceIterator.hasNext()){ UsbDevice device = deviceIterator.next(); int usbVid = device.getVendorId(); int usbPid = device.getProductId(); if((usbVid == ft232rUartVid) && (usbPid ==ft232rUartPid) ){ //Toast.makeText(getApplicationContext(), "Found Usb device: FT232R UART", Toast.LENGTH_LONG).show(); //Toast.makeText(getApplicationContext(), "Now send message USB_ACTION_ATTACH to activity ", Toast.LENGTH_LONG).show(); gLogger.debug("Found Usb device: FT232R UART"); gLogger.debug("Now send message USB_ACTION_ATTACH to activit"); Message foundUsbDeviceAttachMsg =new Message(); foundUsbDeviceAttachMsg.what=usb_action.USB_ACTION_ATTACH.getAction(); mHandler.sendMessage(foundUsbDeviceAttachMsg); bNotFoundUsb = false; break; } else { //Toast.makeText(getApplicationContext(), "Found USB VID="+usbVid+" PID=" + usbPid, Toast.LENGTH_LONG).show(); gLogger.debug("Found USB VID="+usbVid+" PID=" + usbPid); } }//while(deviceIterator.hasNext()){ if(bNotFoundUsb) { try { int sleepTimeInMs = 200; gLogger.debug("Sleep milliseconds: " + sleepTimeInMs); Thread.sleep(sleepTimeInMs); } catch (InterruptedException e) { // TODO Auto-generated catch block //e.printStackTrace(); } } }//while(bNotFoundUsb) }//public void run() } public enum usb_action{ USB_ACTION_UNKNOWN(0), USB_ACTION_ATTACH(1), USB_ACTION_DETACH(2); usb_action (int action) { this.action = action; } private final int action; public int getAction() { return action; } } private void usbActionDetectViaHandler(){ mHandler=new Handler() { public void handleMessage(Message msg) { usb_action curUsbAction = usb_action.values()[msg.what]; //do your own bounds checking switch(curUsbAction) { case USB_ACTION_UNKNOWN: Toast.makeText(getApplicationContext(), "Unkown USB action !", Toast.LENGTH_LONG).show(); break; case USB_ACTION_ATTACH: //TODO: do auto scan hart devices Toast.makeText(getApplicationContext(), "Now should call the HART auto scan", Toast.LENGTH_LONG).show(); break; case USB_ACTION_DETACH: //stop auto detect usb action thread Toast.makeText(getApplicationContext(), "Now destory the usb action detect thread", Toast.LENGTH_LONG).show(); usbActionDetectThread.destroy(); usbActionDetectThread = null; break; default: break; } super.handleMessage(msg); } }; Thread curThread=new Thread(this); curThread.start(); } private void detectUsbDeviceAttach(){ //Method1: this should work, but due to android usb manager bug: //can not get intert usb attach action //so here can not use this method //usbActionDetectViaFilter(); //Method2: use thread + handler to do usb detect usbActionDetectViaHandler(); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //... detectUsbDeviceAttach(); } @SuppressWarnings("deprecation") @Override public void onDestroy() { //... super.onDestroy(); //usbOnDestroy(); //TODO: release current resources? thread? ... if(null != usbActionDetectThread){ if(usbActionDetectThread.isAlive()){ usbActionDetectThread.destroy(); } } } }
可以实现:
循环执行,检测usb的插入
发送都应的message给handler去处理。
然后后续就可以去执行自己要的动作了。