Android——蓝牙通信
16lz
2021-01-24
最近想做一个项目,Android手表将采集到的数据实时的发送到手机上,选择的数据传递方式为蓝牙通信。由于暂时没有手表,所以在两台手机上进行实验。(最终的结果发现通信成功好像跟手机系统有关,后面会具体说道这个问题)
下面开始介绍系统蓝牙服务的使用,最要涉及到使用四个类:
BluetoothAdapter,BluetoothDevice,BluetoothServerSocket,BluetoothSocket.
发现了没,后面的两个类和java的ServerSocket.Socket很类似(不存在继承关系)。他们的用法大致都差不多,只不过创建的方式不一样(仅此而已)。所以在后面会发现一旦获得了BluetoothServerScoket和BluetoothSocket,就和普通的Sokcet编程一样
1.蓝牙的开启
//获得系统蓝牙服务BluetoothAdapter adapter=BluetoothAdpater.getDefaultAdapter();//判断蓝牙是否开启if(!adapter.isEnabled()) adapter.enable();//开启蓝牙//判断蓝牙是否设置为可被其他蓝牙设备发现if(!adapter.isDiscovering()){ Intent i=new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);//设置可被发现的时间 i.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,120000);}startActivity(i);//会弹出一个对话框,询问是否允许被发现adapter.startDiscovery();//开启被发现
2.查找设备
在上面的步骤执行完,开启了蓝牙之后,需要手机查找周围的蓝牙设备
//通过注册广播的方式,将查找的结果返回给当前的Activity,所以先需要定义一个BroadcastReceiver对象,也可以定义一个内部类继承自BroadcastReceiver(个人喜欢直接写匿名内部类)
private BroadcastReceiver receiver=new BroadcastReceiverprivate BroadcastReceiver receiver = new BroadcastReceiver(){ @Override public void onReceiver(Contect context,Intent intent){ //判断当前的动作是什么类型 if(intent.getAction()==BluetoothDevice.ACTION_FOUND); //BluetoothDevices实现了可序列化接口,可以直接放在Intent中传递 BluetoothDevice device=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); //对于得到的deceive,可以获得它的名字等属性,将他们加入到List中显示,以及将deceive用List保存起来 }};//定义了BroadcastReceiver对象receiver,就可以来使用它来监听蓝牙查找情况IntentFilter intentFilter=new IntentFilter(BluetoothDevice.ACTION_FOUND);registerReceiver(receiver,intentFilter);//注册广播
3.创建BluetoothSocket
在上面通过注册广播的方式,我们可以得到周围的deceive信息。
通过的deceive来创建BluetoothSocket
有两种方式
- 通过直接调用:
//UUID="00001101-0000-1000-8000-00805F9B34FB" BluetoothSocket socket=deceive.createRfcommSocketToServiceRecord(UUID.fromString(Config.UUID));
- 利用反射的方式
Method method=device.getClass().getMethod("createRfcommSocket",new Class[]{int.class});socket=method.invoke(device,1);
4.获得BluetoothServerSocket
和获得BluetoothSocket一样两种方式
- 通过直接调用:
//UUID="00001101-0000-1000-8000-00805F9B34FB" BluetoothServerSocket serverSocket=bluetoothAdapter.listenUsingRfcommWithServiceRecord(UUID.fromString(Config.UUID));
- 利用反射的方式
Method method=bluetoothAdapter.getClass().getMethod("listenUsingRfcommOn",new Class[]{int.class});serverSocket=method.invoke(bluetoothAdapter,1);
进行客户端服务端通信
- 服务端需要向获得一个BluetoothServerSocket,上面已经介绍了怎么获取
按照Socket编程的一般方式进行处理即可
//开启一个线程,监听是否有客户端连接(我是将通信放在一个单独的类里,这个类继承自Thread类),run方法里处理,在初始化的时候已经得到bluetoothAdapter,bluetoothServerSocket和一个主线程传递过来的handlepublic void run(){ // boolean getSocket=false;全局变量 //获得服务端的socket while(!getSocket){ socket=bluetoothServerSocket.accept();//是不是和将java Socket编程一样 if(socket!=null) getSocket=true; } //开始读取数据 startReading();}//简单的写写读取过程,异常处理不写了private void startReading(){ while(isReading){//isReading全局变量 if(socket==null) break; InputStream in=socket.getInputStremam(); byte[] bytes=new byte[in.available()]; if(in.read(bytes,0,in.available())>0){ //通过handle将读取到的数据发出去 Message msg=new Message(); msg.what=1;//1表示读取成功 msg.obj=new String(bytes); handle.sendMessage(msg); } //注意read操作会阻塞子线程,所以最好sleep sleep(100);//抛出异常 }}//写操作一样pulic void write(String str){ if(socket!=null){ OutputStream out=socket.getOutputStream(); byte[] bytes=str.getBytes(); out.write(bytes,0,bytes.length); out.flush(); //注意不要关闭读写,可能导致socket连接中断 }}
客户端通信
@Overridepublic void run() { try { socket =device.createRfcommSocketToServiceRecord(UUID.fromString(Config.UUID)); socket.connect(); } catch (IOException e) { e.printStackTrace(); Log.e("TAG", "socket 创建失败" + e.toString()); handler.sendEmptyMessage(Config.STATUES_CONNECT_FAILED); } if (socket.isConnected()) handler.sendEmptyMessage(Config.STATUES_CONNECT_SUCCESS); else handler.sendEmptyMessage(Config.STATUES_CONNECT_FAILED); while (isReading) { try { sleep(100); if (socket == null) continue; if (in == null) in = socket.getInputStream(); byte[] bytes = new byte[in.available()]; if (in.read(bytes,0,in.available()) > 0) { Message msg = new Message(); msg.what = Config.STATUES_READ_SUCCESS; msg.obj = new String(bytes); handler.sendMessage(msg); } } catch (IOException e) { e.printStackTrace(); handler.sendEmptyMessage(Config.STATUES_READ_FAILED); } catch (InterruptedException e) { e.printStackTrace(); } } }
存在的问题
- 用BufferReader包装socket的输入流读取数据出错
- 用发射的方法获取BluetoothServerSocket和BluetoothSocket出问题
- 两台手机,一台华为的P6一台魅蓝note2,华为手机当服务端魅蓝当客户端没问题,但魅蓝但服务端就报错,说没有APN 系统权限之类的
更多相关文章
- Android的IPC方式
- Android的通信机制与网络(一)
- Android跨进程通信 AIDL使用
- android资源文件详解
- 第一行代码 第三章 RecyclerView
- 关于Android使用新浪API的一些说明
- 下载AOSP android源码(最小最快下载方式,跳过编译直接导入Android(
- Android(安卓)Developers:处理音频输出的硬件
- 在Android(安卓)Studio 2.2上集成OpenCV For Android(安卓)SDK