kotlin协程
一个线程的多个协程:
-
一个线程对应多个协程:在 Kotlin 中,协程是协作式的,它们可以在单个线程上启动和运行多个协程。协程通过挂起和恢复操作来协作,而不是通过阻塞线程。
-
一个线程的多个协程可以同时工作:这里的“同时工作”需要从并发和并行的角度来理解。在单核处理器上,协程通过快速切换来给人一种同时工作的错觉,这实际上是并发,而不是并行。当一个协程挂起时(例如,等待 I/O 操作或另一个协程的结果),它会释放线程的控制权,让其他协程在同一线程上运行。这样,尽管在任意给定时刻只有一个协程在执行,但由于挂起操作的非阻塞性质,多个协程可以在同一时间段内完成它们的工作。
线程vs协程【感觉也没啥用】
-
线程:线程是由操作系统管理的,它们是相对重量级的,因为每个线程都有自己的栈空间和上下文。线程的创建、切换和管理需要较多的资源和时间。在单核 CPU 上,线程之间的切换可能会导致性能开销,尤其是在线程数量很多的情况下。
-
协程:协程是用户态的轻量级线程,它们共享同一线程的栈空间,并且协程的切换通常比线程切换要快得多,因为它们不需要涉及操作系统的上下文切换。协程的挂起和恢复操作是由程序控制的,这意味着它们可以在更细的粒度上进行切换,从而实现更高效的并发处理。
蓝牙UUID
UUID就是编号,对应不同服务的一个唯一的编号,用于区分不同的服务及服务特性的个体
服务:比如音频播放
不同的uuid类似网络应用中的端口号分配,例如80是HTTP协议的端口
权限申请与回调
onRequestPermissionsResult
方法 只有在主动调用 requestPermissions
或 ActivityCompat.requestPermissions
请求权限时才会触发。
蓝牙连接与传文件
与已知蓝牙地址设备建立连接,注:以下中服务器端为已知蓝牙地址的目标设备,客户端为自主连接设备。
1.获取目标设备
在客户端(想与已知蓝牙地址连接的设备:
String deviceAddress = "XX:XX:XX:XX:XX:XX"; // 设备 B 的蓝牙地址
BluetoothDevice targetDevice = bluetoothAdapter.getRemoteDevice(deviceAddress);
2.配对设备/监听
在客户端(想与已知蓝牙地址连接的设备:
// 检查设备是否已配对
if (targetDevice.getBondState() != BluetoothDevice.BOND_BONDED) {// 发起配对请求targetDevice.createBond();
}// 监听配对状态
BroadcastReceiver pairingReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);if (device.getAddress().equals(targetDevice.getAddress())) {if (bondState == BluetoothDevice.BOND_BONDED) {Log.d("BluetoothPairing", "Device paired successfully");} else if (bondState == BluetoothDevice.BOND_NONE) {Log.d("BluetoothPairing", "Pairing failed or device unpaired");}}}}
};// 注册广播接收器
IntentFilter pairingFilter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver(pairingReceiver, pairingFilter);
在服务器端:
会弹出弹框,点击确认
3.配对成功,建立socket连接
客户端:
// 使用 UUID 创建蓝牙 socket
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); // 标准串行 UUID
BluetoothSocket socket = null;
try {socket = targetDevice.createRfcommSocketToServiceRecord(uuid);socket.connect(); // 连接服务器端,即目标设备Log.d("BluetoothConnection", "Connected to device B");
} catch (IOException e) {Log.e("BluetoothConnection", "Connection failed: " + e.getMessage());try {socket.close();} catch (IOException ex) {ex.printStackTrace();}
}
服务器端:
// 使用 UUID 创建蓝牙 server socket
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); // 标准串行 UUID
BluetoothServerSocket serverSocket = null;
BluetoothSocket socket = null;
try {serverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord("BluetoothFileTransfer", uuid);Log.d("BluetoothConnection", "Waiting for connection...");socket = serverSocket.accept(); // 阻塞等待客户端连接Log.d("BluetoothConnection", "Connected to device A");
} catch (IOException e) {Log.e("BluetoothConnection", "Connection failed: " + e.getMessage());
} finally {try {serverSocket.close();} catch (IOException e) {e.printStackTrace();}
}
4.进行传输
5.关闭socket
wifi-direct连接
初始化wifiManager,channel--discoverPeeres--requestPeers--connect
如果想指定Group owner(GO):【A:GO,未知mac地址,B:group member,已知mac地址】
1.A创建group
manager.createGroup(channel, new WifiP2pManager.ActionListener() {@Overridepublic void onSuccess() {Log.d("WiFiDirect", "Group created successfully");// 设备 A 现在是 Group Owner}@Overridepublic void onFailure(int reason) {Log.d("WiFiDirect", "Group creation failed: " + reason);}
});
2.设备 A 作为 Group Owner,需要监听来自设备 B 的连接请求,A注册广播监听
BroadcastReceiver receiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);if (networkInfo.isConnected()) {// 连接成功,获取连接信息manager.requestConnectionInfo(channel, connectionInfo -> {if (connectionInfo.groupFormed && connectionInfo.isGroupOwner) {Log.d("WiFiDirect", "Device A is Group Owner");// 设备 A 作为 Group Owner,可以开始文件传输startFileTransferAsGroupOwner();}});}}}
};// 注册广播接收器
IntentFilter filter = new IntentFilter();
filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
registerReceiver(receiver, filter);
3.B请求连接A
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = deviceAAddress; // 设备 A 的 MAC 地址
config.groupOwnerIntent = 0; // 设备 B 不希望成为 Group Ownermanager.connect(channel, config, new WifiP2pManager.ActionListener() {@Overridepublic void onSuccess() {Log.d("WiFiDirect", "Connection request sent to device A");}@Overridepublic void onFailure(int reason) {Log.d("WiFiDirect", "Connection failed: " + reason);}
});
4.B注册监听广播
BroadcastReceiver receiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);if (networkInfo.isConnected()) {// 连接成功,获取连接信息manager.requestConnectionInfo(channel, connectionInfo -> {if (connectionInfo.groupFormed && !connectionInfo.isGroupOwner) {Log.d("WiFiDirect", "Device B is connected to Group Owner");// 设备 B 作为客户端,可以开始文件传输startFileTransferAsClient(connectionInfo.groupOwnerAddress);}});}}}
};// 注册广播接收器
IntentFilter filter = new IntentFilter();
filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
registerReceiver(receiver, filter);
5.建立socket,进行文件传输,关闭socket
A:ServerSocket serverSocket = new ServerSocket(8888); B:Socket socket = new Socket(groupOwnerAddress, 8888); // 连接到 Group Owner
manager.requestConnectionInfo(channel, connectionInfo -> {if (connectionInfo.groupFormed && !connectionInfo.isGroupOwner) {InetAddress groupOwnerAddress = connectionInfo.groupOwnerAddress;Log.d("WiFiDirect", "Group Owner IP: " + groupOwnerAddress.getHostAddress());// 使用 Group Owner 的 IP 地址进行文件传输startFileTransferAsClient(groupOwnerAddress.getHostAddress());}
});