Проблема с входным потоком
Застрял в одном выпуске,
я использую 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 ответа
// Keep listening to the InputStream until an exception occurs
Проблема здесь. Вы должны продолжать чтение из потока, пока не закончится поток или не произойдет исключение. Вам нужно выйти из цикла чтения, если read()
возвращает -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);
}
}
И больше информации о finalize
метод.
РЕДАКТИРОВАТЬ: смелые важны, чем другие предложения.
Чтение комментариев EJP Я понял, почему ваше приложение останавливается, когда вы получаете большие данные: возможно, вам придется очистить буферы перед вызовом read()
, И он говорит, что финализатор может не вызываться системой (я не знаю почему).Как насчет break
цикл, когда read()
возвращенный -1
?
И только сейчас я нашел полезную ссылку о правильном методе чтения потока. Надеюсь, это помогло.
Код цитируется по ссылке
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
это безопаснее (я читал некоторые темы раньше).