前言
在上一篇博文中,针对Android的蓝牙基础知识作了一个简单的梳理。在正式的APP开发过程中,知识转换成成用户能够看得见、摸得着的才能生产力最大化。本章主要针对蓝牙设备的搜索界面作简要的设计、开发。
一、蓝牙搜索界面
通常在APP内的蓝牙搜索中,选择Dialog+listview的方式来显示蓝牙设备的搜索即简洁又美观。常用的Dialog、Listview无法满足需求,因此需要客制化自行封装,以后也可以将这些方法作为一个简易的封装类供其他的项目或者代码参考。
1.1 MyDialog封装
Dialog的封装主要包含两个方面,style和尺寸的封装。
- style
style的封装主要是对Dialog的显示作简要的修改,在res\values\styles.xml中添加以下代码:
- list item
btDevice_list_item.xml主要用于Dialog中的Listview的item布局,每一个item共有三种属性:name,address,bonded,即蓝牙设备名,蓝牙地址,是否绑定。
- MyDialog封装
此自定义的Dialog可以作为后续的其他项目或者其他类型的Dialog类的封装,根据不同的需求,设定其theme即可。
public class MyDialog extends Dialog{
// 这种适合通用
public MyDialog(Context context) {
super(context);
}
// 自定义提醒框样式
public MyDialog(Context context, int themeResId) {
super(context, themeResId);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
- MyDialog的尺寸大小
自定义一个合适的尺寸,满足需求即可,用户或者爱好者可以根据自己的需求及喜好自定义类似的Dialog框图大小及样式。
至此,显示界面已经完成。
二、蓝牙设备搜索
2.1 蓝牙设备的适配器
因添加Listview类,对listview的添加、点击、构建、移除等数据都需要绑定适配器,因此首要的任务根据业务需求自定义适配器。
public class BTDeviceAdapter extends BaseAdapter{
private static final String TAG = "first";
private Context context;
private LayoutInflater mInflater;
private List list;
private BluetoothDevice device;
private static class ViewHolder{
TextView btNameView;
TextView btAddrView;
TextView btBondedView;
}
//构造函数
public BTDeviceAdapter(final Context context, final List list){
super();
this.context = context;
this.list = list;
mInflater = LayoutInflater.from(context);
}
//device list大小
@Override
public int getCount() {
return list.size();
}
//device在list中的位置
@Override
public Object getItem(int position) {
return list.get(position);
}
//device在list中的id
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
//设备是否已经绑定
device = list.get(position);
//如果缓存convertView为空,则需要创建View
if (convertView == null) {
// view创建
convertView = mInflater.inflate(R.layout.btdevice_list_item, null);
holder = new ViewHolder();
holder.btNameView = (TextView) convertView.findViewById(R.id.bt_name);
holder.btAddrView = (TextView) convertView.findViewById(R.id.bt_addr);
holder.btBondedView = (TextView) convertView.findViewById(R.id.bt_bonded);
convertView.setTag(holder);
}else {
holder = (ViewHolder) convertView.getTag();
}
//view属性设置
holder.btNameView.setText(device.getName());
holder.btAddrView.setText(device.getAddress());
if (device.getBondState() == BluetoothDevice.BOND_BONDED){
Log.i(TAG, "设备:" + device.getName() + "已绑定");
holder.btBondedView.setVisibility(View.VISIBLE);
holder.btBondedView.setTextColor(Color.RED);
}else {
holder.btBondedView.setVisibility(View.INVISIBLE);
}
return convertView;
}
}
2.2 蓝牙设备搜索
在所有的工作准备完成后,进入Activity或者fragment中进行蓝牙button的点击搜索工作。
手机蓝牙因为会保存之前已经配对的蓝牙设备,因此可以选择对这些已配对的设备添加到list中,下方附上主要部分的代码。
2.2.1 添加已配对的蓝牙设备
//将已经存在的配对设备先加入列表
Set bondedDevices = adapter.getBondedDevices();
Log.e(TAG, "已绑定设备数为:" + bondedDevices.size());
if (bondedDevices.size() != 0) {
Iterator iterator = bondedDevices.iterator();
while (iterator.hasNext()) {
mlist.add((BluetoothDevice) iterator.next());
}
}
Log.e(TAG,"mlist:" + mlist);//搜索前先将手机以前配对的蓝牙设备列表打印
2.2.2 蓝牙设备搜索并添加
首先将dialog中的listview初始化,并关联适配器。
deviceAdapter = new BTDeviceAdapter(mActivity, mlist);
bt_device_list = (ListView) dialog.findViewById(R.id.bt_device_list);
bt_device_list.setAdapter(deviceAdapter);
adapter.startDiscovery();
2.2.3 蓝牙设备开启广播并添加蓝牙设备到listview
此过程是一个动态添加的过程,在此代码中包括搜索和完成的intent判断。
/**
* 设置静态广播,主要用于接收蓝牙搜索的结果
*/
@Override
public void onResume() {
super.onResume();
//广播过滤
filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
filter.setPriority(Integer.MAX_VALUE);//设置广播的优先级最大
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
try{
String action = intent.getAction();
Log.e(TAG,"接收到蓝牙广播!" + "action = " + action);
switch (action) {
case BluetoothDevice.ACTION_FOUND:
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getName() != null && device != null) {
Log.i(TAG, "device Name: " + device.getName());
Log.i(TAG, "device Addr: " + device.getAddress());
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
Log.e(TAG, "开始添加设备!");
addDevice(device);
}
});
}
break;
case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
System.out.println("ACTION_DISCOVERY_FINISHED");
Log.e(TAG, "扫描完成!");
if (mActivity instanceof Activity) {
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
Log.e(TAG, "finished 开始添加设备!");
Set paired = adapter.getBondedDevices();
Log.e(TAG, "paired = " + paired);
if (paired != null && paired.size() > 0) {
for (BluetoothDevice bonded : paired) {
if (mlist.indexOf(bonded) == -1) {
mlist.add(bonded);
deviceAdapter.notifyDataSetChanged();
}
}
}
Log.e(TAG, "扫描完成后的list: " + mlist);
}
});
}
Log.e(TAG, "扫描完成后的list: " + mlist);
break;
}
}catch (Exception e){
e.printStackTrace();
}
}
};
//注册蓝牙搜索结果的receiver
mActivity.registerReceiver(receiver, filter);
}
添加设备的关键代码
private void addDevice(final BluetoothDevice device) {
boolean deviceFound = false;
for (final BluetoothDevice listDev : mlist) {
if (listDev.getAddress().equals(device.getAddress())) {
deviceFound = true;
break;
}
}
if (!deviceFound) {
if (mlist.indexOf(device) == -1) { //判断设备是否存在list中,不存返回-1
mlist.add(device);
deviceAdapter.notifyDataSetChanged();
}
}
}
2.3 蓝牙搜索结果
通过以上关键部分的代码及搜索过程,可以完成对于蓝牙设备的搜索及添加,当然可以根据个人的需求及爱好针对搜索过程中的一些客制化工作,如将搜索的结果放置在Activity中,dialog加入搜索状态,如正在搜索,搜索完成等,具体添加的位置在btdevice_list_item.xml和BTDeviceAdapter.class中添加状态的判断。
下图为蓝牙设备的搜索结果