android 连接蓝牙模块教程附源码

由于最近项目需要连接蓝牙,类似于智能手环连接蓝牙模块,网上找了些教程,有一些零零散散的程序,自己于是也写了一个能用,然后我发现谷歌有一个蓝牙的sample,一对比突然发现自己写的好low,不严谨。于是就直接 谷歌 例程,修改了部分。首先当初写的时候我有以下几个疑问。

1.如何实现又蓝牙又能接受数据,又能发送数据,这样不会冲突嘛?
2.UUID是啥,蓝牙模块的uuid又是啥?
3.网上程序有客户端又有服务器的蓝牙程序,那我app用的是哪个程序那,蓝牙模块那边不是app不能写程序又怎样?
4.app不断接受数据,我这边怎么判断为一整段数据,并拿来解析。因为在inputSteam.read()这里如果蓝牙没有数据收到的话会出现阻塞的情况,并且一段数据可能多次读取,并不会一次读取完

答案在文章底部揭晓,想直接看答案直接拉到最后。有耐心的可以先看下文,首先我们新建一个BluetoothService类,看看构造器先

public BluetoothChatService(Context context, Handler handler) {
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        mState = STATE_NONE;//蓝牙状态
        mHandler = handler;//用来更新ui
    }

上面蓝牙状态分为3种,分别用来判断当前状态

public static final int STATE_NONE = 0;       // we're doing nothing
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

接下来就是connect()方法了。也就是启动连接

/**
     * Start the ConnectThread to initiate a connection to a remote device.
     *
     * @param device The BluetoothDevice to connect
     * @param secure Socket Security type - Secure (true) , Insecure (false)
     */
    public synchronized void connect(BluetoothDevice device, boolean secure) {
        // 取消之前线程,假设之前有打开过线程
        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, secure);//连接线程
        mConnectThread.start();线程启动
        setState(STATE_CONNECTING);//设置线程为正在连接
        progressDialog.show();//弹出进度dialog
    }

接下来就是看看connectTread里面写了什么

 private class ConnectThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final BluetoothDevice mmDevice;
        private String mSocketType;

        public ConnectThread(BluetoothDevice device, boolean secure) {
            mmDevice = device;//连接必须要有device这个对象
            BluetoothSocket tmp = null;
            mSocketType = secure ? "Secure" : "Insecure";
            // 拿到socket,
            //这里uuid有分安全模式和非安全模式之分,这里目前把他设置成一样
            try {
                if (secure) {
                    tmp = device.createRfcommSocketToServiceRecord(
                            MY_UUID_SECURE);
                } else {
                    tmp = device.createInsecureRfcommSocketToServiceRecord(
                            MY_UUID_INSECURE);
                }
            } catch (IOException e) {
                Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
            }
            mmSocket = tmp;
        }

        public void run() {
            Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
            setName("ConnectThread" + mSocketType);

            // 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) {
                // Close the socket
                try {
                    mmSocket.close();
                } catch (IOException e2) {
                    Log.e(TAG, "unable to close() " + mSocketType +
                            " socket during connection failure", e2);
                }
                connectionFailed();
                return;
            }

            // Reset the ConnectThread because we're done
            synchronized (BluetoothChatService.this) {
                mConnectThread = null;
            }

            // Start the connected thread
            connected(mmSocket, mmDevice, mSocketType);
        }


 }

这里首先构造器拿到Device和secure这两个参数,一个参数是用来获得socket,这样只会才能启动连接,secure来判断连接模式是安全非安全模式。这里如果mmSocket.connect();这个方法没有抛出任何异常的话就可以说明连接成功,接下来调用connected这个方法。这个方法属于BluetoothChatService这个类。

public synchronized void connected(BluetoothSocket socket, BluetoothDevice
            device, final String socketType) {
        Log.d(TAG, "connected, Socket Type:" + socketType);
        progressDialog.dismiss();//连接成功取消进度框
        // 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;
        }

        setState(STATE_CONNECTED);
        // Start the thread to manage the connection and perform transmissions
        mConnectedThread = new ConnectedThread(socket, socketType);
        mConnectedThread.start();

        // 发送已经连接成功的设备名字返回ui线程,即通过ui一开始构造器传进来的mHandler来处理
        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);
    }

那么连接成功后我们应该做什么呢,当然是监听数据啦,这又需要另外开启另一个线程ConnectedThread这个线程

private class ConnectedThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;

        public ConnectedThread(BluetoothSocket socket, String socketType) {
            Log.d(TAG, "create ConnectedThread: " + 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, "temp sockets not created", e);
            }

            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }

        public void run() {
            Log.d(TAG, "BEGIN mConnectedThread");
            byte[] buffer = new byte[1024];
            StringBuilder sb=new StringBuilder();
            int bytes;
            Log.d(TAG,""+mState);
            // Keep listening to the InputStream while connected
            while (mState == STATE_CONNECTED) {

                try {
                    // Read from the InputStream
                    bytes = mmInStream.read(buffer);
                    Log.d("message",new String(buffer,0,bytes));
                    sb.append(new String(buffer,0,bytes));
                    if(sb.charAt(sb.length()-1)=='$'){
                        sb.deleteCharAt(sb.length()-1);
                        mHandler.obtainMessage(Constants.MESSAGE_READ, bytes-1, -1,sb.toString())
                            .sendToTarget();
                        sb.delete(0,sb.length());
                    }
                    // Send the obtained bytes to the UI Activity
                } catch (IOException e) {
                    Log.e(TAG, "disconnected", e);
                    connectionLost();
                    // Start the service over to restart listening mode
                    BluetoothChatService.this.start();
                    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(Constants.MESSAGE_WRITE, -1, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                Log.e(TAG, "Exception during write", e);
            }
        }

哈哈, 大功告成,此时你发现蓝牙模块指示灯从快闪到慢闪,那么现在还缺少什么呢,当然除了接受数据还需要向蓝牙模块发送数据,因为发送数据并不会出现线程阻塞的情况,

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);
    }

这个方法属于BluetoothChatService这个类,只需要这个类实例调用下write就可以了。

这里主要是蓝牙作为客户端的代码,可以看到Google代码对各种异常捕捉考虑情况是很全的。
问题答案:1.当然不会冲突,因为接受数据是在另一个线程。不会产生任何干扰。
2.它是一个唯一的表示符号,打个比喻就像是时间和地点一样总是不能重复的,时间过了就再也没有那个时间了,我估计uuid匹配是部分匹配就能用。蓝牙模块的话我百度到的是


private static final UUID MY_UUID_SECURE =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
3.我们直接用客户端的程序,蓝牙模块那边可能本身就有主从模式可以设置,与之对应,估摸着蓝牙模块那边已经集成好了
4.可以约定个协议,比如你的数据以什么结尾,读到那个结尾就拼接之前所有数据,并发送。可以看博文中ConnectedTread那里

源码地址
http://download.csdn.net/detail/sinat_28676875/9624338

你可能感兴趣的:(android)