Android(安卓)蓝牙通信
Android 蓝牙传文件比较常见,但是官方也给出了基于蓝牙通讯做了个聊天室的sample,BluetoothChat。有兴趣的可以下载看下,很有意思。通讯那块用了特殊的BluetoothSocket。思路跟一般socket通讯一样。必须有服务端和客户端。sample有三个类:BluetoothChat,BluetoothChatService,DeviceListActivity。
BluetoothChat是主界面,可以看到聊天的内容,BluetoothChatService是功能类,实现了主要功能,但本身不是一个service,通过BluetoothChat的handle进行UI交互,DeviceListActivity是查找蓝牙设备的功能类
BluettohtChatService的实现逻辑是启动后就是服务端的在等待客户端来建立连接产生socket,当用户选了某个设备建立连接,那个设备就是客户端了,会把服务端的线程断掉。然后就利用BluetoothSocket通讯。用了状态模式来写,很有参考价值。不过很奇怪是一直有两个线程来等待设备接入,叫安全线程,不安全线程。功能一模一样都。
服务器端的实现
通过调用BluetoothAdapter的listenUsingRfcommWithServiceRecord(String, UUID)方法来获取BluetoothServerSocket(UUID用于客户端与服务器端之间的配对)
调用BluetoothServerSocket的accept()方法监听连接请求,如果收到请求,则返回一个BluetoothSocket实例(此方法为block方法,应置于新线程中)
如果不想在accept其他的连接,则调用BluetoothServerSocket的close()方法释放资源(调用该方法后,之前获得的BluetoothSocket实例并没有close。但由于RFCOMM一个时刻只允许在一条channel中有一个连接,则一般在accept一个连接后,便close掉BluetoothServerSocket)
private finalBluetoothServerSocketmmServerSocket;
publicAcceptThread(){
// UseatemporaryobjectthatislaterassignedtommServerSocket,
// becausemmServerSocketisfinal
BluetoothServerSockettmp= null;
try{
// MY_UUIDistheapp'sUUIDstring,alsousedbytheclientcode
tmp=mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME,MY_UUID);
} catch(IOExceptione){}
mmServerSocket=tmp;
}
public voidrun(){
BluetoothSocketsocket= null;
// Keeplisteninguntilexceptionoccursorasocketisreturned
while( true){
try{
socket=mmServerSocket.accept();
} catch(IOExceptione){
break;
}
// Ifaconnectionwasaccepted
if(socket!= null){
// Doworktomanagetheconnection(inaseparatethread)
manageConnectedSocket(socket);
mmServerSocket.close();
break;
}
}
}
/** Willcancelthelisteningsocket,andcausethethreadtofinish */
public voidcancel(){
try{
mmServerSocket.close();
} catch(IOExceptione){}
}
} 客户端的实现
通过搜索得到服务器端的BluetoothService
调用BluetoothService的listenUsingRfcommWithServiceRecord(String, UUID)方法获取BluetoothSocket(该UUID应该同于服务器端的UUID)
调用BluetoothSocket的connect()方法(该方法为block方法),如果UUID同服务器端的UUID匹配,并且连接被服务器端accept,则connect()方法返回
注意:在调用connect()方法之前,应当确定当前没有搜索设备,否则连接会变得非常慢并且容易失败
private finalBluetoothSocketmmSocket;
private finalBluetoothDevicemmDevice;
publicConnectThread(BluetoothDevicedevice){
// UseatemporaryobjectthatislaterassignedtommSocket,
// becausemmSocketisfinal
BluetoothSockettmp= null;
mmDevice=device;
// GetaBluetoothSockettoconnectwiththegivenBluetoothDevice
try{
// MY_UUIDistheapp'sUUIDstring,alsousedbytheservercode
tmp=device.createRfcommSocketToServiceRecord(MY_UUID);
} catch(IOExceptione){}
mmSocket=tmp;
}
public voidrun(){
// Canceldiscoverybecauseitwillslowdowntheconnection
mBluetoothAdapter.cancelDiscovery();
try{
// Connectthedevicethroughthesocket.Thiswillblock
// untilitsucceedsorthrowsanexception
mmSocket.connect();
} catch(IOExceptionconnectException){
// Unabletoconnect;closethesocketandgetout
try{
mmSocket.close();
} catch(IOExceptioncloseException){}
return;
}
// Doworktomanagetheconnection(inaseparatethread)
manageConnectedSocket(mmSocket);
}
/** Willcancelanin-progressconnection,andclosethesocket */
public voidcancel(){
try{
mmSocket.close();
} catch(IOExceptione){}
}
} 连接管理(数据通信)
分别通过BluetoothSocket的getInputStream()和getOutputStream()方法获取InputStream和OutputStream
使用read(bytes[])和write(bytes[])方法分别进行读写操作
注意:read(bytes[])方法会一直block,知道从流中读取到信息,而write(bytes[])方法并不是经常的block(比如在另一设备没有及时read或者中间缓冲区已满的情况下,write方法会block)
private finalBluetoothSocketmmSocket;
private finalInputStreammmInStream;
private finalOutputStreammmOutStream;
publicConnectedThread(BluetoothSocketsocket){
mmSocket=socket;
InputStreamtmpIn= null;
OutputStreamtmpOut= null;
// Gettheinputandoutputstreams,usingtempobjectsbecause
// memberstreamsarefinal
try{
tmpIn=socket.getInputStream();
tmpOut=socket.getOutputStream();
} catch(IOExceptione){}
mmInStream=tmpIn;
mmOutStream=tmpOut;
}
public voidrun(){
byte[]buffer= new byte[1024]; // bufferstoreforthestream
intbytes; // bytesreturnedfromread()
// KeeplisteningtotheInputStreamuntilanexceptionoccurs
while( true){
try{
// ReadfromtheInputStream
bytes=mmInStream.read(buffer);
// SendtheobtainedbytestotheUIActivity
mHandler.obtainMessage(MESSAGE_READ,bytes,-1,buffer)
.sendToTarget();
} catch(IOExceptione){
break;
}
}
}
/* CallthisfromthemainActivitytosenddatatotheremotedevice */
public voidwrite( byte[]bytes){
try{
mmOutStream.write(bytes);
} catch(IOExceptione){}
}
/* CallthisfromthemainActivitytoshutdowntheconnection */
public voidcancel(){
try{
mmSocket.close();
} catch(IOExceptione){}
}
}
更多相关文章
- Android之取消ViewPage+Fragment的预加载
- android浏览器研究-回退和前进
- 那些年,我们一起踩过的 “Android(安卓)坑”
- Drawable着色问题
- android sdk sdkmanger无界面使用方法(命令行更新SDK)
- Kotlin for Android使用教程(一)
- Service的onStartCommand方法的疑问
- 关于Spring for Android
- Android(安卓)学习之那些年我们遇到的BUG8:ArrayAdapter 直接使用