![](/img/trans.png)
[英]How to handle InputStream and OutputStream via Bluetooth in Android
[英]InputStream not receiving data via Bluetooth
編輯1:MCVE-
我讓我的整個代碼成為主要問題,但是由於要求我提供MCVE,
該設備未收到其他已連接的Android設備發送給它的數據。 代碼沒有經過“ inputStream.read(buffer)”,因為它沒有數據要接收。
發送數據的代碼:
public void sendData(String s) throws IOException{
byte[] byteString=s.getBytes();
outputStream.write(byteString);
outputStream.flush();
Toast.makeText(getApplicationContext(), "Message sent", Toast.LENGTH_SHORT).show();
}
接收:
while (true){
inputStream.read(buffer);
final String str=new String(buffer);
try{
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, str, Toast.LENGTH_SHORT).show();
}
});
}catch (Exception e){
Toast.makeText(context, "Error in reading characters", Toast.LENGTH_SHORT).show();
}
}
另外,我以這種方式連接了我的插座:
Method method = bluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
bluetoothSocket = (BluetoothSocket) method.invoke(bluetoothDevice, 2);
由於連接失敗,因此無法使用端口號1或createRfCcommSocketToServiceRecord。
整個問題:
我正在開發一個需要通過藍牙在兩個android設備之間提供雙向通信功能的應用程序。 發送的數據將是簡單的字符串。
我能夠正確連接兩個設備。 這是我的代碼:
bluetoothAdapter=BluetoothAdapter.getDefaultAdapter();
if(!bluetoothAdapter.isEnabled()){
Intent intent= new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent,1);
}
pairedDevices=bluetoothAdapter.getBondedDevices();
List<String> pairedDevicesList=new ArrayList<String>();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
pairedDevicesList.add(device.toString());
}
}
listView.setVisibility(View.GONE);
btListView.setVisibility(View.VISIBLE);
btListView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, pairedDevicesList));
這會在ListView上顯示所有已配對的設備。 現在選擇這些設備中的任何一個,就可以與以下設備建立連接:
try{
btListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
try {
BluetoothDevice pairedDevicesArray[] = pairedDevices.toArray(new BluetoothDevice[pairedDevices.size()]);
bluetoothDevice = pairedDevicesArray[position];
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Error in getting BT Device", Toast.LENGTH_SHORT).show();
}
try {
ParcelUuid parcelUuidArray[];
List<UUID> uuidList = new ArrayList<UUID>();
Class cl = Class.forName("android.bluetooth.BluetoothDevice");
Class[] params = {};
Method method = cl.getMethod("getUuids", params);
Object[] args = {};
parcelUuidArray = (ParcelUuid[]) method.invoke(bluetoothDevice, args);
for (ParcelUuid u : parcelUuidArray) {
uuidList.add(u.getUuid());
}
uuid = uuidList.get(0);
Toast.makeText(getApplicationContext(), uuid.toString(), Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Error in getting UUIDs", Toast.LENGTH_SHORT).show();
}
try {
Method method = bluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
bluetoothSocket = (BluetoothSocket) method.invoke(bluetoothDevice, 2);
//bluetoothSocket = bluetoothDevice.createRfcommSocketToServiceRecord(uuid);
Toast.makeText(getApplicationContext(), bluetoothSocket.toString(), Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Error in getting BT Socket", Toast.LENGTH_SHORT).show();
}
try {
bluetoothAdapter.cancelDiscovery();
if (!bluetoothSocket.isConnected()) {
bluetoothSocket.connect();
}
Toast.makeText(getApplicationContext(), "CONNECTION SUCCESSFUL!", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Error in connecting", Toast.LENGTH_SHORT).show();
}
btListView.setVisibility(View.GONE);
listView.setVisibility(View.VISIBLE);
try {
outputStream = bluetoothSocket.getOutputStream();
inputStream = bluetoothSocket.getInputStream();
Toast.makeText(getApplicationContext(), "Streams retrieved", Toast.LENGTH_SHORT).show();
//listenForData();
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Error in getting streams", Toast.LENGTH_SHORT).show();
}
final Handler handler = new Handler();
try {
BluetoothSocketListener bluetoothSocketListener = new BluetoothSocketListener(bluetoothSocket, handler, getApplicationContext());
Thread newThread = new Thread(bluetoothSocketListener);
newThread.start();
Toast.makeText(getApplicationContext(), "New Thread Running", Toast.LENGTH_SHORT).show();
}catch(Exception e){
Toast.makeText(getApplicationContext(), "Error in new thread", Toast.LENGTH_SHORT).show();
}
}
});
}catch (Exception e){
Toast.makeText(getApplicationContext(), "Error in 2nd listview", Toast.LENGTH_SHORT).show();
}
此代碼塊末尾的處理程序創建另一個線程,該線程一直運行以接收另一設備發送的數據。 這是該線程的代碼:
public class BluetoothSocketListener implements Runnable {
private BluetoothSocket bluetoothSocket;
private Handler handler;
Context context;
public BluetoothSocketListener(BluetoothSocket socket, Handler handler, Context c){
this.bluetoothSocket=socket;
this.handler=handler;
this.context=c;
}
@Override
public void run(){
int bufferSize=1024;
final byte[] buffer=new byte[bufferSize];
try {
final InputStream inputStream = bluetoothSocket.getInputStream();
int bytesRead = -1;
String message = "";
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, "Listening for data with Stream: "+inputStream.toString(), Toast.LENGTH_SHORT).show();
}
});
while (true){
bytesRead= inputStream.read(buffer);
final String str=new String(buffer);
try{
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, str, Toast.LENGTH_SHORT).show();
}
});
}catch (Exception e){
Toast.makeText(context, "Error in reading characters", Toast.LENGTH_SHORT).show();
}
}
}catch(Exception e){
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, "Error in listening to data", Toast.LENGTH_SHORT).show();
}
});
}
}}
並且,使用MainActivity類中的此函數將數據寫入任何設備上的OutputStream中:
public void sendData(String s) throws IOException{
byte[] byteString=s.getBytes();
outputStream.write(byteString);
outputStream.flush();
Toast.makeText(getApplicationContext(), "Message sent", Toast.LENGTH_SHORT).show();
}
String s是需要發送的字符串。
在兩台單獨的設備上同時運行我的應用程序(一台設備具有Android 5.1.1,另一台設備具有Android 6.0)時,這些設備在兩部手機的已配對設備列表中以及彼此之間的連接情況如何。
顯示所有敬酒,包括“正在運行新線程”和“偵聽數據”,因此代碼確實運行良好。 嘗試發送任何內容時,也會顯示“已發送消息”吐司。 但是數據沒有被接收到(代碼沒有運行過inputStream.read(buffer),作為我在未顯示它之后進行的測試Toast)。
這意味着它已經到了這一點,並等待從InputSream讀取永遠不會出現的數據,即使該數據已成功寫入其他設備上的OutputStream中也是如此。
關閉應用程序后,將顯示錯誤消息“在偵聽數據時出錯”,證明第二個線程一直在正常運行。
誰能告訴我我哪里出問題了? 是我的設備正在從一個套接字查看InputStream時,第二個設備正在將數據發送到另一個套接字。 如果是這樣,我應該如何確保它在正確的套接字上偵聽?
我在StackOverflow上瀏覽了所有類似的問題,甚至檢查了Google的Bluetooth Chat App示例,但找不到任何解決方案。我嘗試了不同的發送字符串的方法(使用OutputStreamWriting並將其編碼為UTF-8等) )並接收它(嘗試逐個字符地接收數據,或在InputStream上使用BufferedReader),但是每次都存在完全相同的問題。 該應用程序的其余部分工作正常。
謝謝。
我對第一篇文章表示歉意。 這是一個答案,如果我正確理解藍牙,則run()函數在CONNECTING階段和CONNECTED之前啟動。 讀取功能從不完整的連接開始。
@Override
public void run(){
int bufferSize=1024;
final byte[] buffer=new byte[bufferSize];
try {
final InputStream inputStream = bluetoothSocket.getInputStream();
int bytesRead = -1;
String message = "";
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, "Listening for data with Stream: "+inputStream.toString(), Toast.LENGTH_SHORT).show();
}
});
while (true){
bytesRead= inputStream.read(buffer);
final String str=new String(buffer);
具體來說,解決您對“聊天”示例的引用以及您編輯該代碼的相似之處。 問題的部分原因是您使用“ Toast”而不是Log.d API,因為它花費了很長時間來處理圖形。
// Constants that indicate the current connection state
public static final int STATE_NONE = 0; // we're doing nothing
public static final int STATE_LISTEN = 1; // now listening for incoming connections
public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
public static final int STATE_CONNECTED = 3; // now connected to a remote device
/** Constructor. Prepares a new BluetoothChat session.
*
* @param context The UI Activity Context
* @param handler A Handler to send messages back to the UI Activity
*/
public BluetoothSPP(Context context, Handler handler) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
mHandler = handler;
}
/** Set the current state of the chat connection
*
* @param state An integer defining the current connection state
*/
private synchronized void setState(int state) {
Log.v(TAG, "BT State changed " + mState + " -> " + state);
mState = state;
// Give the new state to the Handler so the UI Activity can update
mHandler.obtainMessage(Constants.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
觀察mConnectedThread.start()和setState(STATE_CONNECTED)之間的消息處理程序
public synchronized void connected(BluetoothSocket socket, BluetoothDevice
device, final String socketType) {
Log.d(TAG, "BT connected, Socket Type:" + socketType);
// Cancel the thread that completed the connection
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Cancel the accept thread because we only want to connect to one device
if (mSecureAcceptThread != null) {
mSecureAcceptThread.cancel();
mSecureAcceptThread = null;
}
if (mInsecureAcceptThread != null) {
mInsecureAcceptThread.cancel();
mInsecureAcceptThread = null;
}
// Start the thread to manage the connection and perform transmissions
mConnectedThread = new ConnectedThread(socket, socketType);
mConnectedThread.start();
// Send the name of the connected device back to the UI Activity
Message msg = mHandler.obtainMessage(Constants.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(Constants.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
這是讀取線程。
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket, String socketType) {
Log.v(TAG, "BT Connected: " + socketType);
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "BT sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN BT Monitor");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (mState == STATE_CONNECTED) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(Constants.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "BT Monitor Disconnected", e);
connectionLost();
// Start the service over to restart listening mode
BluetoothSPP.this.start();
break;
}
}
Log.i(TAG, "End BT Monitor");
}
Android Studio logcat中的輸出如下所示。 它從未進入while(mState == STATE_CONNECTED)循環。
代碼執行期間Android Studio logcat的輸出
我通過添加處理連接狀態的循環來更正代碼。
public void run() {
Log.i(TAG, "BEGIN BT Monitor");
byte[] buffer = new byte[1024];
int bytes;
while (mState == STATE_CONNECTING){
Log.i(TAG, "BT Monitor Paused");
}
// Keep listening to the InputStream while connected
while (mState == STATE_CONNECTED) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(Constants.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "BT Monitor Disconnected", e);
connectionLost();
// Start the service over to restart listening mode
BluetoothSPP.this.start();
break;
}
}
Log.i(TAG, "End BT Monitor");
}
logcat輸出顯示“ STATE_CONNECTING”循環發生在Log消息表明連接已完成之前15次,而Toast和其他消息在代碼執行之后發生一次(顯示時間依賴性)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.