我尝试使用 Android 开发者网站上的 Android 蓝牙聊天示例连接两个设备。它仅从其中一个设备进行连接,当我尝试从另一台设备进行连接时,它没有连接并弹出一条消息“无法连接:[此处的设备名称]”。
我想知道如果我在两台设备上使用相同的代码,为什么仅从一侧建立连接,而从另一侧被拒绝?
我有 2 台设备 - 1 台运行版本 2.2,1 台运行 v2.3.3。 我的请求始终从运行 2.3.3 的 Galaxy Y 发送到运行 Android 2.2 的 Galaxy fit-v,但反之则不然。这是我的代码:
@Override
public void onActivityResult(int requestCode, int resultCode, final Intent data) {
switch (requestCode) {
case REQUEST_CONNECT_DEVICE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
FaceCardList.requestConnection = true;
FaceCardList.deviceSelected = false;
address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
device = FaceCardList.mBluetoothAdapter.getRemoteDevice(address);
// Attempt to connect to the device
FaceCardList.mChatService.connect(device);
// Get the device MAC address
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
// Bluetooth is now enabled, so set up a chat session
setupChat();
} else {
// User did not enable Bluetooth or an error occured
Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
finish();
}
}
}
我的 BluetoothChat 服务的代码是:
public class BluetoothChatService extends Activity {
private static final String TAG = "BluetoothChatService";
private static final boolean D = true;
// Name for the SDP record when creating server socket
private static final String NAME = "BluetoothChat";
// Unique UUID for this application
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// ("fa87c0d0-afac-11de-8a39-0800200c9a66");
// Member fields
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private AcceptThread mAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
// 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 BluetoothChatService(Context context, Handler handler) {
mAdapter = FaceCardList.mBluetoothAdapter;
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) {
if (D) {
//Log.d(TAG, "setState() " + mState + " -> " + state);
}
mState = state;
// Give the new state to the Handler so the UI Activity can update
mHandler.obtainMessage(FaceCardList.MESSAGE_STATE_CHANGE, state, -1)
.sendToTarget();
}
/**
* Return the current connection state.
*/
public synchronized int getState() {
return mState;
}
/**
* Start the chat service. Specifically start AcceptThread to begin a
* session in listening (server) mode. Called by the Activity onResume()
*/
public synchronized void start() {
if (D) {
Log.d(TAG, "start");
}
// Cancel any thread attempting to make a connection
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Start the thread to listen on a BluetoothServerSocket
if (mAcceptThread == null) {
mAcceptThread = new AcceptThread();
mAcceptThread.start();
}
setState(STATE_LISTEN);
}
/**
* Start the ConnectThread to initiate a connection to a remote device.
*
* @param device
* The BluetoothDevice to connect
*/
public synchronized void connect(BluetoothDevice device) {
if (D) {
Log.d(TAG, "connect to: " + device);
}
// Cancel any thread attempting to make a connection
if (mState == STATE_CONNECTING) {
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Start the thread to connect with the given device
mConnectThread = new ConnectThread(device);
mConnectThread.start();
setState(STATE_CONNECTING);
}
/**
* Start the ConnectedThread to begin managing a Bluetooth connection
*
* @param socket
* The BluetoothSocket on which the connection was made
* @param device
* The BluetoothDevice that has been connected
*/
public synchronized void connected(BluetoothSocket socket,
BluetoothDevice device) {
if (D) {
Log.d(TAG, "######connected");
}
// 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 (mAcceptThread != null) {
mAcceptThread.cancel();
mAcceptThread = null;
}
// Start the thread to manage the connection and perform transmissions
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
// Send the name of the connected device back to the UI Activity
Message msg = mHandler.obtainMessage(FaceCardList.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(FaceCardList.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
/**
* Stop all threads
*/
public synchronized void stop() {
if (D) {
Log.d(TAG, "stop");
}
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if (mAcceptThread != null) {
mAcceptThread.cancel();
mAcceptThread = null;
}
setState(STATE_NONE);
}
/**
* Write to the ConnectedThread in an unsynchronized manner
*
* @param out
* The bytes to write
* @see ConnectedThread#write(byte[])
*/
public void write(byte[] out) {
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (mState != STATE_CONNECTED) {
return;
}
r = mConnectedThread;
}
// Perform the write unsynchronized
r.write(out);
}
/**
* Indicate that the connection attempt failed and notify the UI Activity.
*/
private void connectionFailed() {
setState(STATE_LISTEN);
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(FaceCardList.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(FaceCardList.TOAST, "Unable to connect device");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
/**
* Indicate that the connection was lost and notify the UI Activity.
*/
private void connectionLost() {
setState(STATE_LISTEN);
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(FaceCardList.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(FaceCardList.TOAST, "Device connection was lost");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
/**
* This thread runs while listening for incoming connections. It behaves
* like a server-side client. It runs until a connection is accepted (or
* until cancelled).
*/
private class AcceptThread extends Thread {
// The local server socket
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
// Create a new listening server socket
try {
tmp = mAdapter
.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
// if(!tmp.toString().equalsIgnoreCase(null)){
//
// }
} catch (IOException e) {
//Log.e(TAG, "listen() failed", e);
}
mmServerSocket = tmp;
}
@Override
public void run() {
if (D) {
Log.d(TAG, "BEGIN mAcceptThread" + this);
}
setName("AcceptThread");
BluetoothSocket socket = null;
// Listen to the server socket if we're not connected
while (mState != STATE_CONNECTED) {
try {
socket = mmServerSocket.accept();
} catch (IOException e1) {
// TODO Auto-generated catch block
//e1.printStackTrace();
}
// If a connection was accepted
if (socket != null) {
synchronized (BluetoothChatService.this) {
switch (mState) {
case STATE_LISTEN:
case STATE_CONNECTING:
// Situation normal. Start the connected thread.
connected(socket, socket.getRemoteDevice());
break;
case STATE_NONE:
case STATE_CONNECTED:
// Either not ready or already connected. Terminate
// new socket.
//Log.e("STATE_CONNECTED: service","STATE_CONNECTED: service");
try {
socket.close();
} catch (IOException e) {
//Log.e(TAG,"Could not close unwanted socket", e);
}
break;
}
}
}
}
if (D) {
//Log.i(TAG, "END mAcceptThread");
}
}
public void cancel() {
if (D) {
//Log.d(TAG, "cancel " + this);
}
try {
mmServerSocket.close();
} catch (IOException e) {
//Log.e(TAG, "close() of server failed", e);
}
}
}
/**
* This thread runs while attempting to make an outgoing connection with a
* device. It runs straight through; the connection either succeeds or
* fails.
*/
private class ConnectThread extends Thread {
private BluetoothSocket mmSocket= null;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
System.out.println("my uuid :-"+MY_UUID);
try {
try {
//tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
mmSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
System.out.println("mm socket value :-"+mmSocket);
} catch (IOException e) {
e.printStackTrace();
System.out.println("error in connecting :-"+e.getMessage());
//Log.e(TAG, "create() failed", e);
// TODO Auto-generated catch block
//e.printStackTrace();
}
} catch (SecurityException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
}
// mmSocket = tmp;
System.out.println("mm socket value as temp :-----------------");
}
@Override
public void run() {
//Log.i(TAG, "BEGIN mConnectThread");
setName("ConnectThread");
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
System.out.println("before connection");
mmSocket.connect();
System.out.println("after connection ");
} catch (Exception e) {
System.out.println("in connection failed :-"+e.getMessage());
connectionFailed();
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
//Log.e(TAG,"unable to close() socket during connection failure", e2);
}
// Start the service over to restart listening mode
try {
BluetoothChatService.this.start();
} catch (Exception e2) {
// TODO: handle exception
e2.printStackTrace();
System.out.println("in connection failed start bluetooth chat service :-"+e2.getMessage());
}
return;
}
// Reset the ConnectThread because we're done
synchronized (BluetoothChatService.this) {
mConnectThread = null;
}
// Start the connected thread
connected(mmSocket, mmDevice);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
//Log.e(TAG, "close() of connect socket failed", e);
}
}
}
/**
* This thread runs during a connection with a remote device. It handles all
* incoming and outgoing transmissions.
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
//Log.d(TAG, "create ConnectedThread");
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, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
@Override
public void run() {
//Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream\
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
// XXX !!!
String buffer2 = new String(buffer);
buffer2= buffer2.substring(0, buffer2.length()-3)+"\n";
mHandler.obtainMessage(FaceCardList.MESSAGE_READ, bytes, -1, buffer2.getBytes()).sendToTarget();
} catch (IOException e) {
//Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
}
}
/**
* Write to the connected OutStream.
*
* @param buffer
* The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
// Share the sent message back to the UI Activity
// XXX !!!
String buffer2 = new String(buffer);
buffer2= buffer2.substring(0, buffer2.length()-2);
mHandler.obtainMessage(FaceCardList.MESSAGE_WRITE, -1, -1,
buffer2.getBytes()).sendToTarget();
} catch (IOException e) {
//Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
//Log.e(TAG, "close() of connect socket failed", e);
}
}
}
}
我被困住了。为什么总是从高版本连接到低版本,却不能从低版本连接到高版本?
我已经做到了这一点,我认为当设备可发现的变化时你会失去连接。请务必检查两者中可发现的设备,您可以通过代码启用它。
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,0);
startActivity(discoverableIntent);
Saurabh,请进行此更改并观察其效果:
if (Build.VERSION.SDK_INT < 9) { // VK: Build.Version_Codes.GINGERBREAD is not accessible yet so using raw int value
// VK: 9 is the API Level integer value for Gingerbread
try {
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} else {
Method m = null;
try {
m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", new Class[] { UUID.class });
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
tmp = (BluetoothSocket) m.invoke(device, (UUID) MY_UUID);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
我还认为你的问题不在你的代码中。
两年前我修改了BluetoothChat 示例应用程序。您可以在这里找到修改后的项目 - Bluetooth Chat 和二进制文件:Bluetooth Chat
如果这在您的两个设备之间效果更好,它可能会有所帮助。
我刚刚在 Android 版本 2.3.3 (Nexus One) 和版本 4.0.4 (Galaxy Nexus) 上进行了测试。
我不确定是否直接复制代码并尝试运行它,如果是的话,请记住
android.app.ActionBar
;需要3.0版本。此外,蓝牙通信并不完全是对等的,它是主从通信。