[英]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.