输入流问题

时间:2018-03-20 11:26:00

标签: java android inputstream android-bluetooth bluetooth-socket

陷入一期,

我正在使用BluetoothSocket类,我在输入和输出流的帮助下发送和接收数据。

当应用程序从输入流接收大量数据时,我强行终止我的应用程序,之后我又重新启动了我的应用程序,但是InputStream返回了我以前的数据,这是不再需要的了。如何丢弃旧数据?

对于这个问题有任何解决方案吗?

以下是我的源代码:

public class MyBluetoothService {
private static final String TAG = "MY_APP_DEBUG_TAG";
private Handler mHandler; // handler that gets info from Bluetooth service

// Defines several constants used when transmitting messages between the
// service and the UI.
private interface MessageConstants {
    public static final int MESSAGE_READ = 0;
    public static final int MESSAGE_WRITE = 1;
    public static final int MESSAGE_TOAST = 2;

    // ... (Add other message types here as needed.)
}

private class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;
    private byte[] mmBuffer; // mmBuffer store for the stream

    public ConnectedThread(BluetoothSocket socket) {
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;

        // Get the input and output streams; using temp objects because
        // member streams are final.
        try {
            tmpIn = socket.getInputStream();
        } catch (IOException e) {
            Log.e(TAG, "Error occurred when creating input stream", e);
        }
        try {
            tmpOut = socket.getOutputStream();
        } catch (IOException e) {
            Log.e(TAG, "Error occurred when creating output stream", e);
        }

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    public void run() {
        mmBuffer = new byte[1024];
        int numBytes; // bytes returned from read()

        // Keep listening to the InputStream until an exception occurs.
        while (true) {
            try {
                // Read from the InputStream.
                numBytes = mmInStream.read(mmBuffer);
                // Send the obtained bytes to the UI activity.
                Message readMsg = mHandler.obtainMessage(
                        MessageConstants.MESSAGE_READ, numBytes, -1,
                        mmBuffer);
                readMsg.sendToTarget();
            } catch (IOException e) {
                Log.d(TAG, "Input stream was disconnected", e);
                break;
            }
        }
    }

    // Call this from the main activity to send data to the remote device.
    public void write(byte[] bytes) {
        try {
            mmOutStream.write(bytes);

            // Share the sent message with the UI activity.
            Message writtenMsg = mHandler.obtainMessage(
                    MessageConstants.MESSAGE_WRITE, -1, -1, mmBuffer);
            writtenMsg.sendToTarget();
        } catch (IOException e) {
            Log.e(TAG, "Error occurred when sending data", e);

            // Send a failure message back to the activity.
            Message writeErrorMsg =
                    mHandler.obtainMessage(MessageConstants.MESSAGE_TOAST);
            Bundle bundle = new Bundle();
            bundle.putString("toast",
                    "Couldn't send data to the other device");
            writeErrorMsg.setData(bundle);
            mHandler.sendMessage(writeErrorMsg);
        }
    }

    // Call this method from the main activity to shut down the connection.
    public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "Could not close the connect socket", e);
            }
        }
    }
}

2 个答案:

答案 0 :(得分:1)

// Keep listening to the InputStream until an exception occurs

问题出在这里。您应该继续从流中读取,直到流结束或发生异常。如果read()返回-1,则需要中断读取循环。

目前,您正在读取超出流的结尾,并完全忽略该条件,因此当然上次成功读取时缓冲区中的数据仍然存在。

为了让您的应用程序看到该数据,您还必须忽略读取计数并假设缓冲区已填满,这也是无效的。

答案 1 :(得分:-1)

我认为您应该关闭套接字以管理错误。

我建议你在终结器中执行此操作,如下面的代码。

private class ConnectedThread extends Thread
 {
 private final BluetoothSocket mmSocket;
 private final InputStream mmInStream;
 private final OutputStream mmOutStream;
 private byte[] mmBuffer; // mmBuffer store for the stream
 @override
 protected void finalize() throws Throwable
 {
   try
   {
       cancel();
   }
   finally
   {
        super.finalize();
   }
 }
...

正如我在评论中提到的那样,在关闭套接字之前关闭每个stream更安全。

所以,试试这个cancel()方法。

// Call this method from the main activity to shut down the connection.
 public void cancel()
 {
     try {
        mmInStream.close();
     } catch( NullPointerException | IOException e) {}
    try {
        mmOutStream.close();
     } catch( NullPointerException | IOException e) {}

     try
     {
         mmSocket.close();
     } catch (IOException e) {
         Log.e(TAG, "Could not close the connect socket", e);
     }
 }

more information关于finalize方法。

编辑:大胆的内容比其他建议重要。

阅读EJP的评论我理解为什么你的应用程序在你获得大数据时会停止:你可能必须在调用read()之前清除缓冲区。他说终结者可能不会被系统调用(我不知道为什么)。 break 返回 read() > <{strong> -1 循环?

刚才我找到了一个有用的link关于正确读取流的方法。我希望它有所帮助。

链接引用的代码

private String extract(InputStream inputStream) throws IOException
 {
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
                      byte[] buffer = new byte[1024];
      int read = 0;
      while ((read = inputStream.read(buffer, 0, buffer.length)) != -1) {
          baos.write(buffer, 0, read);
      }   
          baos.flush();
        return new String(baos.toByteArray(), "UTF-8");
  }

另外 虽然在关闭finalizer之前系统关闭streams可能无法调用sockets更安全(我之前读过一些SO线程)。