管理连接
当你成功的连接了两个(或更多)设备时,每一个设备都有一个被连接的BluetoothSocket对象。这是良好的开始,因为你能够在设备之间共享数据。使用BluetoothSocket对象来传输任意数据的过程是简单的:
1. 分别通过getInputStream()和getOutputStream()方法来获得通过套接字来处理传输任务的InputStream和OutputStream对象;
2. 用read(byte[])和write(byte[])方法来读写流中的数据。
当然,有更多实现细节要考虑。首先和前提,对于所有数据流的读写应该使用专用的线程。这是重要的,因为read(byte[])和write(byte[])方法是阻塞式调用。Read(byte[])方法在从数据流中读取某些数据之前一直是阻塞的。write(byte[])方法通常是不阻塞的,但是对于流的控制,如果远程设备不是足够快的调用read(byte[])方法,并且中间缓存被填满,那么write(byte[])方法也会被阻塞。因此,你的线程中的主循环应该是专用于从InputStream对象中读取数据。在线程类中有一个独立的公共方法用于初始化对OutputStream对象的写入操作。
示例
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
上例中,构造器用于获取必要的流对象,并且一旦被执行,线程就会等待通过InputStream对象传入的输入。当read(byte[])方法从数据流中返回指定字节的数据时,使用来自其父类的Handler把该数据会被发送给主Activity,然后返回继续等待流中的更多的字节。
发送输出数据就像在主Activity中调用线程的write()方法一样简单,并且给该方法传入要发送的字节。然后这个方法简单的调用write(byte[])方法把数据发送给远程设备。
线程的cancel()方法是至关重要的,以便该连接在任何时候能够通过关闭BluetoothSocket对象来终止。这个方法在使用完蓝牙连接时应该始终被调用。
使用配置来工作
从Android3.0开始,蓝牙API就包含了对用蓝牙配置来进行工作的支持。Bluetooth Profile是设备之间基于蓝牙进行通信的无线接口规范。其中一个示例是Hands-Free配置。对于一个连接到无线耳机的移动电话,移动电话和蓝牙耳机都必须支持Hands-Free配置。
你能够实现BluetoothProfile接口,来编写你自己的支持特殊蓝牙配置的类。Android蓝牙API提供了对以下蓝牙配置的实现:
· Headset(耳机):该配置提供了对用于移动电话的蓝牙耳机的支持。Android提供了BluetoothHeadset类,这个类是一个代理,它通过进程间通信(IPC)来控制蓝牙耳机服务。它包含了Bluetoot Headset和Hands-Free(v1.5)配置。BluetoothHeadset类包含了对AT命令的支持。关于AT命令的更多讨论,请看“Vendor-specific AT commands”。
· A2DP:Advanced Audio Distribution Profile的缩写。它定义如何流化高品质的音频,并让音频流在通过蓝牙连接在设备之间传输。Android提供了BluetoothA2dp类,它一个通过IPC来控制的蓝牙A2DP服务的代理。
· Health Device:Android4.0(API Level 14)中引入了对Bluetooth Health Device Profile(HDP)的支持。它能够让你创建一个跟支持蓝牙的健康保健设备进行蓝牙通信的应用程序,这些健康保健包括:心率监护仪、血压测量仪、体温计、体重秤等。对应它支持的设备的列表和它们相应的设备数据规范,蓝牙联盟的网站:www.bluetooth.org。注意,这些值也是参考了ISO/IEEE11073-20601[7]规范中命名编码规范附件中的名为MDC_DEV_SPEC_PROFILE_*规范。
以下是使用配置进行工作的基本步骤
1. 获取默认的适配器;
2.使用getProfileProxy()方法来建立一个与配置相匹配的配置代理对象的连接。在下面的示例中,配置代理对象是一个BluetoothHeadset对象实例;
3.创建一个BluetoothProfile.ServiceListener监听器,该监听器会在它们连接到服务器或中断与服务器的连接时,通知BluetoothProfile的IPC客户端。
4.在onServiceConnected()事件中,获得对配置代理对象的处理权;
5.一旦获得配置代理对象,就可以用它来监视连接的状态,并执行与配置有关的其他操作。
例如,以下代码片段显示如何连接一个BluetoothHeadset代理对象,以便控制Headset配置:
BluetoothHeadset mBluetoothHeadset;
// Get the default adapter
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// Establish connection to the proxy.
mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);
private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
mBluetoothHeadset = (BluetoothHeadset) proxy;
}
}
public void onServiceDisconnected(int profile) {
if (profile == BluetoothProfile.HEADSET) {
mBluetoothHeadset = null;
}
}
};
// ... call functions on mBluetoothHeadset
// Close proxy connection after use.
mBluetoothAdapter.closeProfileProxy(mBluetoothHeadset);