看了半年的蓝牙,真的是快半年了,刚开始学安卓就是直接看蓝牙模块真的是难为自己了。今天终于实现了蓝牙的数据接收并显示在了手机上,所以需要稍微记录一下。
分为以下步骤:
a. 获取本机蓝牙
BA =BluetoothAdapter.getDefaultAdapter();
b. 打开蓝牙
Intent turnOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); turnOn.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 10); mContext.startActivity(turnOn);
c. 获取已经匹配蓝牙
pairedDevices = BA.getBondedDevices(); //得到的pairedDevices应该是一个数组类型 for(BluetoothDevice device : pairedDevices) { list1.add("已配对:" + device.getName() + "/" + device.getAddress()); mainList1.add(device); adapter1.notifyDataSetChanged();
其中mainList1为ArrayList类型,泛型为BluetoothDevice为了在点击ListView时获取
d. 扫描未匹配蓝牙
1. 添加广播过滤器,打开广播
IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_FOUND); //搜索到蓝牙设备 filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); mContext.registerReceiver(mReceiver, filter);
同时需要在广播响应中设置:
class Receiver extends 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(!mainList1.contains(device)){ list1.add("未配对:" + device.getName() + "/" + device.getAddress()); mainList1.add(device); adapter1.notifyDataSetChanged(); } } } }
2. 开始扫描
BA.startDiscovery();
其中:
a. 广播中获取动作
String action = intent.getAction();
b. 获取扫描到的蓝牙设备
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
e. 点击设备
lv1.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { Log.d("检测:","mainList1:"+mainList1.get(i)); BA.cancelDiscovery(); connectDevice(mainList1.get(i)); String deviceName=mainList1.get(i).getAddress().toString(); StoreData.put(MainActivity.this,"address",deviceName); new Thread(){ @Override public void run(){ String deviceName=StoreData. get(MainActivity.this,"address","").toString(); BluetoothDevice device=BA.getRemoteDevice(deviceName); communicate(device); DataTransport(); } }.start(); String address=mainList1.get(i).toString(); Log.d("检测:","getRemoteAddress:"+BA.getRemoteDevice(address).getBondState()); } });
f. 配对设备
1. 判断状态
mBluetoothDevice.getBondState() == BluetoothDevice.BOND_NONE
2. Method creMethod(连接蓝牙)
Method creMethod = BluetoothDevice.class .getMethod("createBond"); Log.e("TAG", "开始配对"); creMethod.invoke(mBluetoothDevice);
g. 存储蓝牙设备Mac地址
String deviceName=mainList1.get(i).getAddress().toString(); StoreData.put(MainActivity.this,"address",deviceName);
其中StoreData.put()为自定义函数,继承的
SharedPreferences类
h. 通过Mac地址找回设备对象(getRemoteDevice(String str))
String deviceName=StoreData. get(MainActivity.this,"address","").toString();
BluetoothDevice device=BA.getRemoteDevice(deviceName);
i. 判断状态(同f.1)
j. 新建线程并完成以下步骤
new Thread(){ @Override public void run(){ String deviceName=StoreData. get(MainActivity.this,"address","").toString(); BluetoothDevice device=BA.getRemoteDevice(deviceName); communicate(device); DataTransport(); } }.start();
k. 获取本机uuid
UUID uuid= UUID.fromString(SPP_UUID);
l. 新建BluetoothSocket
btSocket=device.createRfcommSocketToServiceRecord(uuid);
m. 连接BluetoothSocket
btSocket.connect();
n. 获取BluetooSocket的输入输出流
inputStream=btSocket.getInputStream(); outputStream=btSocket.getOutputStream();
其中:
对于imn三步骤,涉及到输入输出数据传输,因此需要在try/catch结构中实现
o. 将输入输出流读取成可处理格式
length = inputStream.read(recvBuffer);
p. 其中length为int型,recvBuffer是byte[]型
q. 将输入输出流转化为二进制,即对recvBuffer进行处理
public class functions { /** * 用于建立十六进制字符的输出的大写字符数组 */ private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5','6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; /** * 用于建立十六进制字符的输出的小写字符数组 */ private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; public static String BytesToString(byte[] inHex, int nOff, int nLen) { int i; StringBuilder strResult = new StringBuilder(); strResult.append(""); for (i = 0; i < nLen; i++) { strResult.append(String .valueOf(DIGITS_UPPER[(0xF0 & inHex[nOff + i]) >>> 4])); strResult.append(String .valueOf(DIGITS_UPPER[inHex[nOff + i] & 0x0F])); } return strResult.toString(); } }
r. 通过handler发送出带有二进制信息的Message
Message message = new Message(); message.obj =functions.BytesToString(recvBuffer, 0, length); //将输入二进制数转化为十六进制数 handler.sendMessage(message);
s. 回到handleMessage处理接收到的Message
Handlerhandler=new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { String str3 = (String) msg.obj; StoreData sdata = new StoreData(); sdata.setContent(str3); EventBus.getDefault().post(sdata); return false; } });
1. 通过EventBus将数据发送至显示层
String str3 = (String) msg.obj; StoreData sdata = new StoreData(); sdata.setContent(str3); EventBus.getDefault().post(sdata);
2. 在显示层通过onEventMainThread()函数接收、读取并显示
public void onEventMainThread(StoreData sdata) { tv1.setText(sdata.mMsg); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); }
大工告成,当然还有环境配置之类的。目前虽然遇到过这些问题,但是也还没系统性搞明白怎么处理。以后再说了。