最近想做一个项目,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 BroadcastReceiver
private 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和一个主线程传递过来的handle
public 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连接中断
}
}
客户端通信
@Override
public 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 系统权限之类的