界面设计完了,下面开始着重于蓝牙搜索与连接功能。
本文主要参考了SDK中的sample。源码可在oschina.net查看,附上链接:http://www.oschina.net/code/explore/android-2.2-froyo/com/example/android/BluetoothChat
下面介绍一下有关蓝牙的使用。
1. 获取蓝牙权限
要使用蓝牙先得获取蓝牙权限,在AndroidManifest.xml中添加BLUETOOTH和BLUETOOTH_ADMIN
2. 获取 BluetoothAdapter类
可以通过getBluetoothAdapter() 的方法来获取BluetoothAdapter
private BluetoothAdapter mBluetoothAdapter = null;
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
Toast.makeText(this, "蓝牙不可用", Toast.LENGTH_LONG).show();
finish();
return;
}
3. 打开蓝牙
使用 isEnabled() 来检测蓝牙是否打开。调用startActivtyForResult() Intent来打开蓝牙,其中REQUEST_ENABLE_BT定义为一个大于0 的整数。执行该语句会弹出一个对话框,点击“允许”会返回RESULT_OK ,即打开蓝牙;而点击“拒绝”则会返回RESULT_CANCLE,也就是不同意打开蓝牙。
private static final int REQUEST_ENABLE_BT = 1;
if (!mBluetoothAdapter.isEnabled()) {
Intent OpenBTIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(OpenBTIntent, REQUEST_ENABLE_BT);
}
4. 查找已配对设备
private BluetoothAdapter mBtAdapter;
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
Set pairedDevices = mBtAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
for (BluetoothDevice device : pairedDevices) {
mPairedDevicesArrayAdapter.add(device.getName() + "\n"
+ device.getAddress());
}
5. 查询蓝牙设备
然后通过startDiscovery()方法启动蓝牙设备的搜寻。这是个异步方法,调用的时候立刻就会返回,大约会持续12秒。为了获得搜寻的结果,必须在用户自己的Activity中注册一个BroadcastReceiver
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
mNewDevicesArrayAdapter.add(device.getName() + "\n"
+ device.getAddress());
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED
.equals(action)) {
setProgressBarIndeterminateVisibility(false);
setTitle(R.string.select_device);
if (mNewDevicesArrayAdapter.getCount() == 0) {
String noDevices = getResources().getText(
R.string.none_found).toString();
mNewDevicesArrayAdapter.add(noDevices);
}
}
}
};
}
为ACTION_FOUND设置监听过滤,注册BroadcastReciver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
this.registerReceiver(mReceiver, filter);
Activity结束后调用cancelDiscovery()可停止搜索,并注销广播。
protected void onDestroy() {
super.onDestroy();
if (mBtAdapter != null) {
mBtAdapter.cancelDiscovery();
}
this.unregisterReceiver(mReceiver);
}
6. 建立连接
客户端(Client)作为发起连接的一方,我们可以调用createRfcommSocketToServiceRecord(UUID)来获得蓝牙套接字。蓝牙串口通信,有一个固定的UUID,为00001101-0000-1000-8000-00805F9B34FB。
通过调用connect()来发起一个连接,这是一个阻塞调用,所以必须新建一个线程。
private static final UUID MY_UUID = UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB");
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
try {
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
}
mmSocket = tmp;
}
public void run() {
setName("ConnectThread");
mAdapter.cancelDiscovery();
try {
mmSocket.connect();
} catch (IOException e) {
connectionFailed();
try {
mmSocket.close();
} catch (IOException e2) {
}
BluetoothCarService.this.start();
return;
}
synchronized (BluetoothCarService.this) {
mConnectThread = null;
}
connected(mmSocket, mmDevice);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
}
}
}
建立点击蓝牙列表的监听。搜索蓝牙会消耗大量的资源,所以在准备建立连接之前需要取消搜索。
private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
public void onItemClick(AdapterView> av, View v, int arg2, long arg3) {
mBtAdapter.cancelDiscovery();
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17);
Intent intent = new Intent();
intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
setResult(Activity.RESULT_OK, intent);
finish();
}
};
7. 管理连接
连接建立之后,就可以在客户端和蓝牙模块之间进行通讯。通过调用getOutPutStream()来获取OutputStream,通过write(byte[])写入数据。
因为write(byte[])也为阻塞调用,所以也必须建立一个新的线程。
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
OutputStream tmpOut = null;
try {
tmpOut = socket.getOutputStream();
} catch (IOException e) {
}
mmOutStream = tmpOut;
}
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
mHandler.obtainMessage(MainActivity.MESSAGE_WRITE, -1, -1,
buffer).sendToTarget();
} catch (IOException e) {
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
}
}
}
}