安卓蓝牙开发笔记

话说自己今年的清明节过的很带劲,总结起来就是:清明时节雪纷纷,码农编程欲断魂。虽然有很多事情需要做,但是哥们找我帮忙,我还是腾出一天多的时间帮忙写了一个APP,主要以蓝牙为基础实现主要功能,短时间内也只是实现了界面显示切换和主要功能。虽然去年写过类似的APP,但是后来不幸手欠格式化硬盘时忘了备份,而且今年再用谷歌的蓝牙开发源码貌似更新了一些细节,今年用起来连接流畅多了,但是去年什么样子老衲也是无从记起了。
为了以后在遇到蓝牙开发方便,我决定写一下这次的理解。

本文主要讨论谷歌提供的BluetoothChatService类(个人认为这才是官方文档里最亮的星)。
首先,你要问操作系统要一个BluetoothAdapter,即本地蓝牙适配器,通俗点解释它就好比是你手里的手机,有了手机你才可以拨号、打电话等等与手机有关的功能。有了这个适配器你就可以发现其他蓝牙设备,获取已配对的蓝牙列表,让你的设备可以被发现等等功能。我们需要用一行代码来获取它。

mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

这行代码出现在BluetoothChatService的构造函数中
虽然构造函数中大家会看到还有一个handler在这里扎眼,大家可以先认为它就相当于一个信鸽,将产生的消息传递给activity,handler不觉明历的话,它的机制和作用大家可以自己去搜搜,很多帖子讲的不错,这里就不在赘述了。
再往下看,大家会注意到start、connect、connected、stop等几个成员方法,细心的朋友会注意到,这几个方法的中心都是围绕相应三个内部线程类的操作,是的,本类的精华就在于这三个内部线程类,且听老衲一一道来。
AcceptThread:服务端的线程
先说一下这个UUID,我们可以理解为电话号码(你给我打电话,咱们俩得有通话的唯一标识),这个UUID就像是蓝牙相互连接的“电话号码”,有了这个唯一标识,电话才能打得出去,接收的到。
学过网络socket编程的朋友,还记的第一次学socket的时候,服务器端的socket有一个accept()方法吗?这个类就是实现服务端的接收操作的,run方法里面调用了蓝牙socket的accept方法,让你的“手机”可以被“打通”。然后如果是连接中的状态就可以继续管理连接了。

public void run() {
            setName("AcceptThread" + mSocketType);

            BluetoothSocket socket = null;

            // Listen to the server socket if we're not connected
            while (mState != STATE_CONNECTED) {
                try {
                    // This is a blocking call and will only return on a
                    // successful connection or an exception
                    socket = mmServerSocket.accept();
                } catch (IOException e) {
                    break;
                }

                // 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(),
                                        mSocketType);
                                Log.e("connected:","accept");
                                break;
                            case STATE_NONE:
                            case STATE_CONNECTED:
                                // Either not ready or already connected. Terminate new socket.
                                try {
                                    socket.close();
                                } catch (IOException e) {
                                }
                                break;
                        }
                    }
                }
            }

        }

ConnectThread:客户端的线程
说完服务端,就到了客户端,同样它也少不了UUID(显然,一厢情愿是谈不了“恋爱”的,需要两情相悦)。值得注意的是,务必保证两端的UUID是一样的!!!
首先run方法停掉了蓝牙可以发现,这是因为一边被发现,一边去连接可能会减慢连接,甚至导致失败。随后调用蓝牙socket的connect方法连接服务端连接成功后开始管理连接。

public void run() {
            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) {
                }
                connectionFailed();
                Log.e("error",e.getMessage());
                return;
            }

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

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

ConnectedThread:管理连接的线程
去年第一次接触的时候,当时还年轻,自己看到这里犯了嘀咕,怎么还有?再往下看豁然开朗。回想网络编程,服务端和客户端是分离的,所以我们会在各自连接好之后就可以开始进行操作了(当然一般也都是另起一个线程进行),可是这是要实现互连的蓝牙,服务端和客户端是绑定在一起的,谷歌工程师进行了封装,将流的读写合并在了一起。Run方法中出现的是会引起阻塞的读操作,写数据方法单独成一个方法。

public void run() {
            Log.e("connected:","run");
            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);
                    Log.e("connectedmg","length:"+bytes);
                    Log.e("connectedmg",new String(buffer));
                    // Send the obtained bytes to the UI Activity
                    mHandler.obtainMessage(MainActivity.MESSAGE_READ, bytes, -1, buffer)
                            .sendToTarget();
                } catch (IOException 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(MainActivity.MESSAGE_WRITE, -1, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
            }
        }

最后只得提醒的是,如果是6.0以上的系统需要动态申请蓝牙权限,记得在运行时做一些调整。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值