Android中的蓝牙连接与两台设备

Posted

技术标签:

【中文标题】Android中的蓝牙连接与两台设备【英文标题】:Bluetooth connection in Android with two devices 【发布时间】:2014-03-17 20:34:15 【问题描述】:

我只是想知道是否可以通过蓝牙同时连接多个设备。我的意思是一台设备想同时与其他两台设备共享一些信息,是否可以通过蓝牙? (我有 2 个 Nexus 5 一个 Nexus 7)。

这是我的发起人:

    if(requestCode ==  REQUEST_CONNECT_DEVICE)
        // When DeviceListActivity returns with a device to connect
        if (resultCode == Activity.RESULT_OK) 
            // Get the device MAC address
            ArrayList<String> address = data.getExtras().getStringArrayList(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
            // Get the BLuetoothDevice object
            BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address.get(0));
            BluetoothDevice device2 = mBluetoothAdapter.getRemoteDevice(address.get(1));
            ArrayList<BluetoothDevice> devices=new ArrayList<BluetoothDevice>();
            devices.add(device);
            devices.add(device2);
            // Attempt to connect to the device
            mChatService.connect(devices);
        
    

这是我的蓝牙聊天服务:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.UUID;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class BluetoothChatService 
    // Debugging
    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 = "BluetoothChatMulti";

    // Member fields
    private final BluetoothAdapter mAdapter;
    private final Handler mHandler;
    private AcceptThread mAcceptThread;
    private ConnectThread mConnectThread;
    private ConnectedThread mConnectedThread;
    private int mState;

    private ArrayList<String> mDeviceAddresses;
    private ArrayList<ConnectedThread> mConnThreads;
    private ArrayList<BluetoothSocket> mSockets;
    private boolean bothConnected=false;
    /**
     * A bluetooth piconet can support up to 7 connections. This array holds 7 unique UUIDs.
     * When attempting to make a connection, the UUID on the client must match one that the server
     * is listening for. When accepting incoming connections server listens for all 7 UUIDs. 
     * When trying to form an outgoing connection, the client tries each UUID one at a time. 
     */
    private ArrayList<UUID> mUuids;

    // 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 = BluetoothAdapter.getDefaultAdapter();
        mState = STATE_NONE;
        mHandler = handler;
        mDeviceAddresses = new ArrayList<String>();
        mConnThreads = new ArrayList<ConnectedThread>();
        mSockets = new ArrayList<BluetoothSocket>();
        mUuids = new ArrayList<UUID>();
        // 7 randomly-generated UUIDs. These must match on both server and client.
        mUuids.add(UUID.fromString("b7746a40-c758-4868-aa19-7ac6b3475dfc"));
        mUuids.add(UUID.fromString("2d64189d-5a2c-4511-a074-77f199fd0834"));

    

    /**
     * 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(InitiatorActivity.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(ArrayList<BluetoothDevice> devices) 


        // 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;
*/
        // Create a new thread and attempt to connect to each UUID one-by-one.    
        for (int i = 0; i < 2; i++) 
            try 
                mConnectThread = new ConnectThread(devices.get(i), mUuids.get(i));
                mConnectThread.start();


             catch (Exception e) 
            
        


    

    /**
     * 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");

        //Commented out all the cancellations of existing threads, since we want multiple connections.
        /*
        // 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();
        // Add each connected thread to an array
        mConnThreads.add(mConnectedThread);

        // Send the name of the connected device back to the UI Activity
        Message msg = mHandler.obtainMessage(InitiatorActivity.MESSAGE_DEVICE_NAME);
        Bundle bundle = new Bundle();
        bundle.putString(InitiatorActivity.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) 
        // When writing, try to write out to all connected threads 
        for (int i = 0; i < mConnThreads.size(); i++) 
            try 
                // Create temporary object
                ConnectedThread r;
                // Synchronize a copy of the ConnectedThread
                synchronized (this) 
                    if (mState != STATE_CONNECTED) return;
                    r = mConnThreads.get(i);
                
                // Perform the write unsynchronized
                r.write(out);
             catch (Exception e)              
            
        
    

    /**
     * Indicate that the connection attempt failed and notify the UI Activity.
     */
    private void connectionFailed() 
        setState(STATE_LISTEN);
        // Commented out, because when trying to connect to all 7 UUIDs, failures will occur
        // for each that was tried and unsuccessful, resulting in multiple failure toasts.

        // Send a failure message back to the Activity
        Message msg = mHandler.obtainMessage(InitiatorActivity.MESSAGE_TOAST);
        Bundle bundle = new Bundle();
        bundle.putString(InitiatorActivity.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(InitiatorActivity.MESSAGE_TOAST);
        Bundle bundle = new Bundle();
        bundle.putString(InitiatorActivity.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 
        BluetoothServerSocket serverSocket = null;

        public AcceptThread() 
        

        public void run() 
            if (D) Log.d(TAG, "BEGIN mAcceptThread" + this);
            setName("AcceptThread");
            BluetoothSocket socket = null;
            try 
                // Listen for all 7 UUIDs
                for (int i = 0; i < 2; i++) 
                    serverSocket = mAdapter.listenUsingRfcommWithServiceRecord(NAME, mUuids.get(i));
                    socket = serverSocket.accept();
                    if (socket != null) 
                        String address = socket.getRemoteDevice().getAddress();
                        mSockets.add(socket);
                        mDeviceAddresses.add(address);
                        connected(socket, socket.getRemoteDevice());
                                           
                
             catch (IOException e) 
                Log.e(TAG, "accept() failed", e);
            
            if (D) Log.i(TAG, "END mAcceptThread");
        

        public void cancel() 
            if (D) Log.d(TAG, "cancel " + this);
            try 
                serverSocket.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 final BluetoothSocket mmSocket;
        private final BluetoothDevice mmDevice;
        private UUID tempUuid;

        public ConnectThread(BluetoothDevice device, UUID uuidToTry) 
            mmDevice = device;
            BluetoothSocket tmp = null;
            tempUuid = uuidToTry;

            // Get a BluetoothSocket for a connection with the
            // given BluetoothDevice
            try 
                Method m = device.getClass().getMethod("createRfcommSocket", new Class[] int.class);
                tmp = (BluetoothSocket) m.invoke(device, 1);    
             catch (NoSuchMethodException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
             catch (IllegalAccessException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
             catch (IllegalArgumentException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
             catch (InvocationTargetException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
            
            mmSocket = tmp;
        

        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
                mmSocket.connect();
             catch (IOException e) 
                if (tempUuid.toString().contentEquals(mUuids.get(1).toString())) 
                    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
                BluetoothChatService.this.start();
                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;
        

        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
                    mHandler.obtainMessage(InitiatorActivity.MESSAGE_READ, bytes, -1, buffer)
                            .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
                mHandler.obtainMessage(InitiatorActivity.MESSAGE_WRITE, -1, -1, buffer)
                        .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);
            
        
    

【问题讨论】:

【参考方案1】:

Android 上的蓝牙允许一次连接多个设备。这些限制与蓝牙无线电频道和正在使用的任何更高级别的协议(例如 RFCOMM)有关。在我的 SmartGear 应用程序中,我同时连接了 2 个蓝牙游戏控制器 (RFCOMM),它工作正常。

【讨论】:

非常感谢您的回答。你能提供一个示例代码吗?我的应用程序不用于商业目的。它只是为了一项科学工作。 您需要 Android 中一般蓝牙连接的示例代码还是专门用于 2 连接案例的示例代码?就我而言,我连接了 0、1 或 2 个控制器,因此我为每个连接生成一个新线程,只要连接处于活动状态,它就会运行。我不确定您是否会从我的代码中受益,除非您有具体的疑问需要我提供帮助。 嗨,是的,我需要这样的东西。它是关于安全的多部分计算。我有一般的蓝牙连接,它工作得很好。我需要提供三个设备 A-B A-C B-C 之间的连接 如果您的连接已经正常工作,那么唯一缺少的就是线程。你需要使用:new Thread(new Runnable() public void run() ).start(); 我正在尝试修改蓝牙聊天示例。但是我什至无法成功提供多个连接。【参考方案2】:

蓝牙不能同时支持多个连接。在 android 中存在点对点连接。如果您想将相同的数据发送到多个设备。从蓝牙示例中解决此问题:

1.从集合或数组中的DevicelistActivity存储中获取所有最近的设备mac地址。

2.通过设备的mac地址,一一连接设备。

3.当连接一个设备并完成数据发送后,终止先前的连接并建立新的连接并连接另一台设备。

4.希望这些信息对你有所帮助。

【讨论】:

您好,谢谢您的回答:)我在夏天之前完成了它;)但我的解决方案是一样的;) @user12492 如果你对我的回答满意,请投票给我的回答。

以上是关于Android中的蓝牙连接与两台设备的主要内容,如果未能解决你的问题,请参考以下文章

Android - 两台设备之间的通信

在android中记录蓝牙传输活动

目前连接的蓝牙设备android

求教Android蓝牙与多个设备连接问题

有没有办法通过 iOS/swift 中的蓝牙以编程方式连接 android 和 IOS 设备?

一起Talk Android吧(第二百八十九回:Android中的BLE开发:蓝牙连接设备三)