![](/img/trans.png)
[英]Android java.io.IOException: write failed: EBADF (Bad file number)
[英]Java.io.IOException, “bad file number” USB connection
我正在設置Android手機和其他設備之間的USB配件連接。 只是來回發送字節進行測試。 我一開始就得到了一些明確的溝通,但它總是最終會死於Java.io.IOException: write failed: EBADF (Bad file number)"
在一秒左右之后。有時讀數仍然存在但是寫作死了;其他都是死。
我沒有像谷歌文檔那樣做任何超級想象,閱讀和寫作的事情:
初始連接(在廣播接收器內,我知道這部分至少在最初工作):
if (action.equals(ACTION_USB_PERMISSION))
{
ParcelFileDescriptor pfd = manager.openAccessory(accessory);
if (pfd != null) {
FileDescriptor fd = pfd.getFileDescriptor();
mIn = new FileInputStream(fd);
mOut = new FileOutputStream(fd);
}
}
讀:
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
byte[] buf = new byte[BUF_SIZE];
while (true)
{
try {
int recvd = mIn.read(buf);
if (recvd > 0) {
byte[] b = new byte[recvd];
System.arraycopy(buf, 0, b, 0, recvd);
//Parse message
}
}
catch (IOException e) {
Log.e("read error", "failed to read from stream");
e.printStackTrace();
}
}
}
});
thread.start();
寫作:
synchronized(mWriteLock) {
if (mOut !=null && byteArray.length>0) {
try {
//mOut.flush();
mOut.write(byteArray, 0, byteArray.length);
}
catch (IOException e) {
Log.e("error", "error writing");
e.printStackTrace();
return false;
}
}
else {
Log.e(TAG, "Can't send data, serial stream is null");
return false;
}
}
錯誤堆棧跟蹤:
java.io.IOException: write failed: EBADF (Bad file number)
W/System.err(14028): at libcore.io.IoBridge.write(IoBridge.java:452)
W/System.err(14028): at java.io.FileOutputStream.write(FileOutputStream.java:187)
W/System.err(14028): at com.my.android.transport.MyUSBService$5.send(MyUSBService.java:468)
W/System.err(14028): at com.my.android.transport.MyUSBService$3.onReceive(MyUSBService.java:164)
W/System.err(14028): at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:781)
W/System.err(14028): at android.os.Handler.handleCallback(Handler.java:608)
W/System.err(14028): at android.os.Handler.dispatchMessage(Handler.java:92)
W/System.err(14028): at android.os.Looper.loop(Looper.java:156)
W/System.err(14028): at android.app.ActivityThread.main(ActivityThread.java:5045)
W/System.err(14028): at java.lang.reflect.Method.invokeNative(Native Method)
W/System.err(14028): at java.lang.reflect.Method.invoke(Method.java:511)
W/System.err(14028): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
W/System.err(14028): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
W/System.err(14028): at dalvik.system.NativeStart.main(Native Method)
W/System.err(14028): Caused by: libcore.io.ErrnoException: write failed: EBADF (Bad file number)
W/System.err(14028): at libcore.io.Posix.writeBytes(Native Method)
W/System.err(14028): at libcore.io.Posix.write(Posix.java:178)
W/System.err(14028): at libcore.io.BlockGuardOs.write(BlockGuardOs.java:191)
W/System.err(14028): at libcore.io.IoBridge.write(IoBridge.java:447)
W/System.err(14028): ... 13 more
我已經遍布整個地方,因此我知道它不是太明顯,例如收到另一個許可請求(因此文件流在讀取期間重新初始化)。 流也沒有關閉,因為我從來沒有在我的代碼中的任何地方發生(現在)。 我也沒有得到任何分離或附加事件(如果發生,我會記錄)。 似乎沒有什么不同尋常的; 它就死了。
我想也許這是一個並發問題,所以我玩鎖和睡覺,沒有嘗試過。 我不認為這是一個吞吐量問題,因為它仍然發生在我每次讀取(兩端)時,並且一次讀取一個數據包(超慢比特率)。 某種程度上緩沖區是否有可能在另一端被超限? 我該如何清除這個? 我可以訪問另一端的代碼,它也是一個Android設備,使用主機模式。 如果它很重要,我也可以發布該代碼 - 標准批量轉移。
這款手機是否對Android配件模式支持不足? 我嘗試了兩部手機,它們都失敗了,所以我懷疑是這樣的。
我想知道在Android上寫入或讀取USB時一般會導致此錯誤的原因是什么?
我在我的代碼中遇到了同樣的問題,我發現它發生是因為FileDescriptor對象是GCed。
我通過在Activity(或Service)中添加ParcelFileDescriptor字段來解決此問題。
我檢查了你的第一個代碼片段和你所基於的代碼,后者在Thread中有ParcelFileDescriptor字段。
我想如果您編輯下面的代碼,它運作良好。
ParcelFileDescriptor mPfd;
...
if (action.equals(ACTION_USB_PERMISSION))
{
mPfd = manager.openAccessory(accessory);
if (mPfd != null) {
FileDescriptor fd = mPfd.getFileDescriptor();
mIn = new FileInputStream(fd);
mOut = new FileOutputStream(fd);
}
}
它最終成為一個線程問題。 我需要更恰當地隔離甚至寫作,而不僅僅是閱讀。
我最終使用此代碼作為基礎。
好吧,我注意到的一些事情似乎與我對開放附件模式所做的不同,我主要關注USB配件的文檔,所以它應該非常相似,就是你的mIn.read(buf);
應該是mIn.read(buf, 0, 64);
我所知道的。
另外,你應該在你的類聲明中聲明thread myThread;
。 然后在創建新的FileInput/OutputStream
之后的BroadcastReceiver
,讓myThread = new thread(myHandler, myInputStream);
跟着我的myThread.start();
。
現在我注意到您正在與線程中的UI直接通信。 您應該使用一個處理程序,而不是線程將與之通信,然后這將與您的UI進行通信,至少從我讀過的內容開始。
這是我的處理程序和線程的示例:
final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg){
}
};
private class USB_Thread extends Thread {
Handler thisHandler;
FileInputStream thisInputStream;
USB_Thread(Handler handler, FileInputStream instream){
thisHandler = handler;
thisInputStream = instream;
}
@Override
public void run(){
while(true) {
try{
if((thisInputStream != null) && (dataReceived == false)) {
Message msg = thisHandler.obtainMessage();
int bytesRead = thisInputStream.read(USB_Data_In, 0, 63);
if (bytesRead > 0){
dataReceived = true;
thisHandler.sendMessage(msg);
}
}
}
catch(IOException e){
}
}
}
}
此外,還有一些演示打開附件的應用在這里 。 它們可能有助於您理解配件模式。
並且還存在已知問題,即應用程序未以編程方式接收ACTION_USB_ACCESSORY/DEVICE_ATTACHED
的BroadcastReceiver。 它只會通過清單文件接收它。 你可以在這里和這里找到更多相關信息 。
我實際上沒有測試將dataReceived
變量放在處理程序中,並且最近才更改了我的代碼部分。 我測試了它並且沒有用,所以試着記住我讀過的內容,我認為這不是關於在線程內進行通信的變量,而是嘗試使用類似.setText()
東西。 我更新了我的代碼,在線程中包含dataReceived=true
。 然后,處理程序將用於更新UI上的項目,例如TextView
等。
線
FileDescriptor fd = mFileDescriptor.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
usbThread = new USB_Thread(mHandler, mInputStream);
usbThread.start();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.