需求分析:
1、开机启动,等待客户端连接
2、检测到有客户端连入就开始监听数据
3、监听到数据之后,进行相应的处理
4、检测到客户端断开,就重新开始等待客户端连接
1、开机启动,等待客户端连接
监听开机广播,然后启动服务,等待客户端连接,暂时为了测试,使用 Activity 手动启动服务;
2、检测到有客户端连入就开始监听数据
因为都是耗时操作,所以这些工作我么都需要放到线程中进行操作
监听客户端连入
public void startBluetoothServerSocket() {
new BluetoothServerThread().start();
}
class BluetoothServerThread extends Thread {
BluetoothServerThread() {
if (mBsServerSocket == null) {
try {
if (false) {
mBsServerSocket = BluetoothAdapter.getDefaultAdapter().listenUsingRfcommWithServiceRecord(BluetoothAdapter.getDefaultAdapter().getName(), UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66"));
} else {
mBsServerSocket = BluetoothAdapter.getDefaultAdapter().listenUsingInsecureRfcommWithServiceRecord(BluetoothAdapter.getDefaultAdapter().getName(), UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66"));
}
} catch (IOException e) {
Log.d("liuxiuting", "fail to get serversocket of bluetooth" + e.toString());
e.printStackTrace();
}
}
}
@Override
public void run() {
super.run();
if (mBsServerSocket != null) {
Log.d("liuxiuting", "mBsServerSocket!=null");
try {
btSocket = mBsServerSocket.accept();
Log.d(TAG, "有客户端连接到我们");
onConnectSucceed(btSocket);
} catch (IOException e) {
Log.d(TAG, "fail to mBsServerSocket.accept()" + e.toString());
}
}
}
监听客户端消息
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket, String socketType) {
Log.d(TAG, "create ConnectedThread: " + socketType);
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer;
int bytes;
String str;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
// 此处每次读取1024个字节,切记每次必须new一下buffer,
// 或者在读之前将 buffer 清空,否则会出现脏数据
buffer = new byte[1024];
bytes = mmInStream.read(buffer);
str = new String(buffer,"UTF-8");
// 得到数据,我们开始做具体操作
DataProcessManager.getInstance().dataProcess(str.trim());
Log.e(TAG, str.trim());
} catch (IOException e) {
// 如果走到这儿,说明客户端断开了连接,我们需要把一些对象close,
// 这些对象包括 输入输出流,获取到的socket,以及我们监听客户端
// 连接时创建的 mBsServerSocket
// 然后开始重新监听
Log.e(TAG, "disconnected", e);
// Start the service over to restart listening mode
cancel();
closeBluetoothServerSocket();
break;
}
}
try {
Thread.sleep(1000);
startBluetoothServerSocket();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
3、 对接收到的数据进行分析处理
传过来的数据大概分两种:
一种是键值,最多是三位数,另外一种就是字符串用于输入文本,所以我就用字符串长度来区分,为了防止文本少于四个字符,所以我在传输文本之前在文本开头添加了四个 0;
public void dataProcess(String code){
if(code.length()>=4){
code = code.substring(4);//去掉开头的四个 0
new RemoteControlTextThread(code).start();
}else{
new RemoteControlNumThread(code).start();
}
// 不同的功能用不同的线程来实现,方便后续的扩展
}
具体的功能实现:
@Override
public void run() {
super.run();
try {
remoteCommand = "input keyevent "+remoteCode;
Runtime.getRuntime().exec(remoteCommand);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
super.run();
try {
remoteCommand = "input text "+remoteText;
Runtime.getRuntime().exec(remoteCommand);
} catch (IOException e) {
e.printStackTrace();
}
}
还有需要注意的一点就是应用需要系统权限,否则命令无法执行成功;
总结
服务端这一块东西从技术上分析就是Socket,和 adb 命令执行,执行部分相对简单,容易出错的部分就只有Socket 部分了,我觉得需要注意的地方有三点;
1、判断客户端断开的时机,知道断开后重新监听之前,需要将所有的资源释放掉,否则会监听失败;
2、数据的获取,buffer 数据每次都需要清空,否则会出现脏数据;
3、一些耗时的操作,一些互不影响的需要并行的操作,都需要用线程来实现,这一块并没有很多相同的任务需要执行,线程池暂时不需要;