我有两台通过蓝牙连接的设备。我想从设备向另一个设备发送更多字符串,但方法read()不能正常工作(仅当我想读取最后一个字符串时)。
奇怪的是,它适用于:
inStream.read(keyRead);
outStream.write(answer.getBytes(charsetCod));
inStream.read(sizeRead);
inStream.read(messageRead);
inStream.read(timeSent);
但它只在应用程序执行时才起作用:
int byteRead = inStream.read(alreadyReceived);
有人可以帮助我理解为什么它不读? (抱歉我的英语不好)
这是代码:
当我从InputStream读取时:
public void run(BluetoothDevice device) {
Log.i(TAG, "Sono nel run del ConnectedThread");
dev_recipient = btAdapter.getName(); // se sto per leggere, il destinatario sono io
dev_sender = device.getName();
Log.i(TAG, "il mittente è: " + dev_sender);
Log.i(TAG, "Il destinatario è " + dev_recipient);
mac_sender = device.getAddress();
mac_recipient = btAdapter.getAddress();
byte[] keyRead = new byte[50];
byte[] sizeRead = new byte[10];
byte[] timeSent = new byte[100];
byte[] alreadyReceived = new byte[500];
String message;
String sentTime;
while (true) { // finchè è connesso
try {
messDB = new MessagesDatabase(context);
messDB.getWritableDatabase();
Log.i(TAG, "Destinatario: Ricevo la chiave del messaggio");
inStream.read(keyRead);
String keyS = new String(keyRead);
int indkeyS = keyS.indexOf("#end", 0);
String key = keyS.substring(0, indkeyS);
Log.i(TAG, "Stringa chiave del messaggio: " + key);
Log.i(TAG, "Controllo se ho già ricevuto il messaggio");
if(messDB.existsMess(key)){
Log.i(TAG, "Destinatario: Il messaggio è già stato ricevuto");
Log.i(TAG, "Destinatario: Informa il mittente di non inviare");
answer = "NO#end";
outStream.write(answer.getBytes(charsetCod));
outStream.flush();
run(device);
}
else {
Log.i(TAG, "Destinatario: Il messaggio non è stato mai ricevuto");
Log.i(TAG, "Destinatario: Informa il mittente di inviare");
answer = "YES#end";
outStream.write(answer.getBytes(charsetCod));
outStream.flush();
Log.i(TAG, "Destinatario: Ricevi la grandezza del messaggio");
inStream.read(sizeRead);
String s = new String(sizeRead);
int ss = s.indexOf("#end", 0);
Log.i(TAG, "indice di #end: " + ss);
String sz = s.substring(0, ss);
Log.i(TAG, sz);
int size = Integer.parseInt(sz);
Log.i(TAG, "La grandezza del messaggio è " + size);
byte[] messageRead = new byte[size];
Log.i(TAG, "Destinatario: Ricevi il messaggio");
inStream.read(messageRead);
message = new String(messageRead); // converte i bytes in String
Log.i(TAG, "Ricevuto messaggio dall'inputStream: " + message);
Log.i(TAG, "Destinatario: ottengo data e ora di ricezione messaggio");
long receivedTime = System.currentTimeMillis();
DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss:SSS");
Date dt = new Date(receivedTime);
String receivedTimeString = df.format(dt);
Log.i(TAG, "Il messaggio è stato ricevuto alle " + receivedTimeString);
Log.i(TAG, "Destinatario: Ricevo ora e data di invio messaggio");
inStream.read(timeSent);
sentTime = new String(timeSent);
int senInd = sentTime.indexOf("#end", 0);
String sentTimeSender = sentTime.substring(0, senInd);
Log.i(TAG, "Il messaggio è stato inviato il: " + sentTimeSender);
Log.i(TAG, "Destinatario: Ricevo gli already received");
int byteRead = inStream.read(alreadyReceived);
Log.i(TAG, "sono stati letti " + byteRead + " byte");
String ar = new String(alreadyReceived);
Log.i(TAG, ar);
int arInd = ar.indexOf("#end", 0);
String myAr = ar.substring(0, arInd);
Log.i(TAG, myAr);
String allReceived = myAr.concat(";mac_recipient");
Log.i(TAG, "AlreadyReceived: " + allReceived);
Log.i(TAG, "Destinatario: Informo il mittente che ho ricevuto il messaggio");
String answOk = "OK#end";
outStream.write(answOk.getBytes(charsetCod));
String path = saveMessageAsFile(key, message);
Log.i(TAG, "Destinatario: Invio l'intent per mostrare all'utente il messaggio ricevuto");
Intent intent = new Intent(ACTION_MESS_READ);
intent.putExtra("key_mess", key);
intent.putExtra("messRead", message);
intent.putExtra("sender", dev_sender);
context.sendBroadcast(intent);
Log.i(TAG, "Intent concluso");
addMessageToDb(key, message, dev_sender, dev_recipient, receivedTimeString, sentTime, path, allReceived, size);
read(device);
}
}
catch (IOException e) {
Log.e(TAG, "Disconnesso!", e);
connectionLost();
ManageConnections.this.start(); // riavvia la connessione
break;
}
}
}
写作:
public void write(final String key, final BluetoothDevice device) {
dev_sender = btAdapter.getName();
dev_recipient = device.getName();
mac_sender = btAdapter.getAddress();
mac_recipient = device.getAddress();
final byte[] answerClient = new byte[10];
final byte[] ricevuto = new byte[10];
try {
final String keyy = key.concat("#end");
final byte[] keyWrite = keyy.getBytes(charsetCod);
outStream.write(keyWrite); // invia la chiave del messaggio
outStream.flush();
Log.i(TAG, "Mittente: ho inviato la chiave del messaggio al destinatario, aspetto la risposta..");
try {
inStream.read(answerClient);
final String answerC = new String(answerClient);
Log.i(TAG, answerC);
final int ansInd = answerC.indexOf("#end", 0);
Log.i(TAG, "indice: " + ansInd);
answer = answerC.substring(0, ansInd);
Log.i(TAG, "Mittente: la risposta del dispositivo: " + answer);
if (answer == "NO") {
Log.i(TAG, "Mittente: Il messaggio è già stato ricevuto, non inviare");
aggiornaAlreadyReceived(device.getAddress(), key);
}
else {
Log.i(TAG, "Mittente: Il messaggio non è stato ricevuto, invia..");
messDB = new MessagesDatabase(context);
messDB.getWritableDatabase();
final Messaggio m = messDB.getMessage(key);
Log.i(TAG, "Mittente: Invio la grandezza del messaggio");
final int size = m.getSize();
Log.i(TAG, "La grandezza è " + size);
final String sizeString = String.valueOf(size);
final String ss = sizeString.concat("#end");
Log.i(TAG, ss);
final byte[] sizeByte = ss.getBytes(charsetCod);
outStream.write(sizeByte);
outStream.flush();
Log.i(TAG, "Mittente: Invio il messaggio");
final byte[] message = m.getMessage().getBytes(charsetCod);
final long sentTime = System.currentTimeMillis();
outStream.write(message);
outStream.flush();
Log.i(TAG, "Mittente: Invio data e ora in cui il messaggio è stato mandato");
final DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss:SSS");
final Date dt = new Date(sentTime);
final String sent = df.format(dt);
final String sentime = sent.concat("#end");
final byte[] sentTimeByte = sentime.getBytes(charsetCod);
outStream.write(sentTimeByte);
outStream.flush();
Log.i(TAG, "Mittente: Invio gli already_received");
final String myAlRec = m.getAlreadyReceived();
Log.i(TAG, myAlRec);
final String myAlreadyRec = myAlRec.concat("#end");
Log.i(TAG, myAlreadyRec);
final byte[] allReceived = myAlreadyRec.getBytes(charsetCod);
outStream.write(allReceived);
outStream.flush();
Log.i(TAG, "Mittente: Aspetto che il destinatario mi informi dell'arrivo del messaggio");
String ric = "";
inStream.read(ricevuto);
final String ricev = new String(ricevuto);
Log.i(TAG, "Il destinatario risponde con " + ricev);
final int ricInd = ricev.indexOf("#end", 0);
ric = ricev.substring(0, ricInd);
Log.i(TAG, ric);
if(ric == "OK") {
Log.i(TAG, "Mittente: Il destinatario ha ricevuto il messaggio");
aggiornaAlreadyReceived(mac_recipient, key);
}
else Log.i(TAG, "Mittente: Il messaggio non è stato ricevuto");
Log.i(TAG, "Mittente: Invio l'intent per informare l'utente che il messaggio è stato inviato");
final Intent intent = new Intent(ACTION_MESS_WRITE);
intent.putExtra("key_mess", key);
intent.putExtra("recipient", dev_recipient);
intent.putExtra("ric", ric);
context.sendBroadcast(intent);
Log.i(TAG, "Mittente: Intent concluso");
}
}
catch (final Exception e) {
Log.e(TAG, "Errore");
e.printStackTrace();
}
}
catch (final IOException e) {
Log.e(TAG, "Eccezione durante la scrittura dell'id del messaggio", e);
e.printStackTrace();
final Intent intent = new Intent(ACTION_NO_MESSAGE);
intent.putExtra("key_mess", key);
context.sendBroadcast(intent);
}
}
答案 0 :(得分:4)
public class BlueTooth
{
public String tag = "Bluetooth";
public static final UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
public BluetoothAdapter adapter;
public BluetoothDevice device = null;
public BluetoothSocket socket = null;
//public static final char ESC = (char) 27;
//public static final char CR = (char) 13;
//public static final char LF = (char) 10;
public BlueTooth(String MAC)
{
this(MAC,null);
}
@TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1)
public BlueTooth(String MAC, byte[] pin)
{
try
{
adapter = BluetoothAdapter.getDefaultAdapter();
// wait for enable this is not very correct
if (!adapter.isEnabled()) {
adapter.enable();
SystemClock.sleep(5000);
if (!adapter.isEnabled()) throw new IOException("Bluetooth is off");
}
if (!BluetoothAdapter.checkBluetoothAddress(MAC)) throw new Exception("Err MAC adress (" + MAC + ")");
device = adapter.getRemoteDevice(MAC);
// this is only for testing purpouse i dont use this
if (pin!=null)
setPin(pin);
// i have some trouble with my device on different OS
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.HONEYCOMB)
socket = device.createInsecureRfcommSocketToServiceRecord(uuid);
else
socket = device.createRfcommSocketToServiceRecord(uuid);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
finally
{
}
}
public void setPin(byte[] pin)
{
try
{
Method setPin = device.getClass().getMethod("setPin", byte[].class);
setPin.invoke(device, pin);
Log.i("BlueTooth", "PIN is set: "+new String(pin));
}
catch (Exception e)
{
e.printStackTrace();
}
}
@Override
protected void finalize() throws Throwable
{
disconnect();
super.finalize();
}
// Android REfs recommend to cancel discover
public boolean connect()
{
try
{
while (adapter.isDiscovering())
{
adapter.cancelDiscovery();
Thread.sleep(1000);
}
socket.connect();
return true;
}
catch(Exception e)
{
throw new RuntimeException(e.getMessage(),e);
}
}
// After write is good(only for shure for next write) to clear buffer with flush
public void write(byte[] in) throws Exception
{
socket.getOutputStream().write(in, 0, in.length);
socket.getOutputStream().flush();
}
// Wait for incomming data
// if is something in the buffer start count but max 3sec
// 3 sec is defined by my device vendor for reply
//
// after it we something on buffer.
// you must realize the reading is on the fly
// there for you must wait after read to next data sleep(1mxec)
// until data are available
// then return
public byte[] read() throws Exception
{
int treshHold = 0;
while (socket.getInputStream().available()==0 && treshHold<3000)
{
Thread.sleep(1);
treshHold++;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.reset();
while (socket.getInputStream().available() > 0)
{
baos.write(socket.getInputStream().read());
Thread.sleep(1);
}
return baos.toByteArray();
}
// This is little low
// after disconnect you must create
// new socket
// so after disconnect you are not able to use connect
// withous createRFcommSocket
public void disconnect() throws Exception
{
if (socket != null) socket.close();
}
}
答案 1 :(得分:0)
不能说我完全理解你的代码,但得到了一些可能有用的提示。
请检查Managing a Connection部分。如你所见;
您应该使用专用线程进行所有流读取和 写作。这很重要,因为 read(byte [])和 write(byte []) 方法是阻止来电。 read(byte [])将阻止直到有 某些从流中读取。 write(byte [])通常不会 阻止,但如果远程设备不阻止,则可以阻止流量控制 完全调用 read(byte []),中间缓冲区就是 充分。因此,线程中的主循环应专用于读取 来自InputStream。
首先,为了更好的设计,您应该使用专用线程进行阅读,并使用另一个进行写作。您应该将形成数据的部分分开,将其写入OutputStream并从InputStream中读取。
当我开始编写 Reader Thread 时,我将读取(byte [])的InputStream方法阻塞执行,直到有所需的字节数。但事实并非如此。我发现它确实会阻塞,直到从流中读取“某些东西”(我以前错过的部分)。
你有一个大小为500的字节数组。当你“不能”(在这种情况下)读取部分流时,日志中的条目是什么:
int byteRead = inStream.read(alreadyReceived);
Log.i(TAG, "sono stati" + byteRead + " byte");
我的观点是:考虑一下你的包裹; 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09,您通过OutputStream写入并刷新它。你仍然可以在一次read()调用中得到只有的一部分(甚至是1字节 - > 0x01),并在下一次read()中得到其余部分(0x02和其余部分)呼叫。在这种情况下,byteRead
将等于1,alreadyReceived[0]
将为0x01,其他元素将为0