学习安卓开发半年了,一直苦于没有记录下来,以后安卓学习当中遇到的问题与解决方案都记载在这里吧。
2021/3/3
安卓的蓝牙模块在连接时遇到了不少的坑,利用串口UUID可以顺利的连接到另一台安卓设备上并进行字节流的通讯,但是无法使用UUID连接电脑的蓝牙。调试了两天,最后发现可以通过反射机制获取服务器套接字,以下是我自己封装的方法:
// 获取服务器套接字
public static BluetoothSocket getSocketFromDevice(BluetoothDevice device, int channel) {
BluetoothSocket ans = null;
// 反射
try {
Method getSocket = device.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
ans = (BluetoothSocket) getSocket.invoke(device, channel);
} catch (NoSuchMethodException e) {
e.printStackTrace();
Log.d(TAG, "getSocketFromDevice: " + "获取Socket异常:NoSuchMethodException");
} catch (IllegalAccessException e) {
e.printStackTrace();
Log.d(TAG, "getSocketFromDevice: " + "获取Socket异常:IllegalAccessException");
} catch (InvocationTargetException e) {
e.printStackTrace();
Log.d(TAG, "getSocketFromDevice: " + "获取Socket异常:InvocationTargetException");
}
return ans;
}
不过这个方法虽然解决了UUID的问题,但是又带来了通道channel的选择问题,经过我的暴力测试,发现当channel=1时,可以连接电脑,channel=2时,可以连接另一台手机,channel=3时,手机或电脑都能进行连接。。。
回调机制的使用让我的服务Service变得更加灵活,通过自定义回调接口,可以指定服务运行成功或失败的不同分支,做出响应的UI响应,这个还是非常方便的。如:我要调用蓝牙的connect方法,这是个阻塞调用,所以我在服务里开了一个线程专门处理,当连接成功时显示出设备信息,连接失败时也做出相应的提示,这时候就可以利用两个接口,分别在实例化时传入不同的代码即可。示例如下
自定义的OnClick接口:
public interface OnBack {
void onBack();
}
服务中的蓝牙连接方法:
public void connect(BluetoothDevice device, OnBack success, OnBack failed) {
new Thread(new Runnable() {
@Override
public void run() {
try {
BT_SOCKET = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
e.printStackTrace();
// 出现异常就调用fail的onBack方法
failed.onBack();
return;
}
try {
MyLog.d(TAG, "连接中Service...By UUID");
BT_SOCKET.connect();
MyLog.d(TAG, "连接成功service");
} catch (IOException e) {
e.printStackTrace();
// 出现异常就调用fail的onBack方法
failed.onBack();
return;
}
// 连接成功
// 工作完成,执行成功相应的回调方法
success.onBack();
}
}
}).start();
}
调用的时候可以这样:
BT_BINDER.connect(device, () -> {
// 连接成功后执行的代码
}, () -> {
// 如果连接失败,就会执行这里的代码
});
调用时如果不想使用Lambda表达式,也可以使用匿名内部类实现OnClick接口。
下面附上笔记2:安卓红外线
学习笔记2:红外线与美的空调协议