andorid 蓝牙相关

ops/2025/3/4 10:45:14/

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());}
});


http://www.ppmy.cn/ops/163020.html

相关文章

GitHub高效搜索工具

[GitHub项目搜索工具] 一款开发者专属的星矿探测仪! 你是否还在用stars:>1000手动筛选GitHub项目? 你是否经常为了找一个合适的开源库翻遍搜索结果? 这个工具或许能改变你的代码资源发掘方式… 🌟 痛点洞察 在GitHub的3.28亿个…

CogVLM: Visual Expert for Pretrained Language Models 简读

背景与模型信息 其原始论文《CogVLM: Visual Expert for Pretrained Language Models》由 THUDM 团队在 2023 年 11 月发布于 arXiv。 模型动机 传统视觉语言模型通常使用浅层对齐方法,通过简单投影层将图像特征映射到语言模型的输入空间。这种方法可能限制了视觉…

计算机视觉|ConvNeXt:CNN 的复兴,Transformer 的新对手

一、引言 在计算机视觉领域,卷积神经网络(Convolutional Neural Networks,简称 CNN)长期以来一直是核心技术,自诞生以来,它在图像分类、目标检测、语义分割等诸多任务中都取得了令人瞩目的成果。然而&…

ArcGIS操作:11 计算shp矢量面的质心坐标

1、打开属性表 2、添加字段 3、设置字段名称、类型 4、选择创建的字段,计算几何 5、选择属性质心的x坐标、坐标系(y坐标同理) 注意:计算坐标一般使用的是地理坐标系(投影坐标系转地理坐标系教程:ArcGIS操作…

C++对象特性

#构造函数 和 析构函数 构造函数:主要为对象属性赋值 语法:类名(){} 注意: 1.无返回值也无void 2.函数名称与类名相同 析构函数 语法:~类名(){} 注意: 1.无返回值也无void 2.不可以有参数&#xff0c;不可发生重载 class Person { public://构造函数Person(){cout<<&quo…

Wayland Architecture Wayland架构

本文只是翻译&#xff0c;原文地址Chapter 3. Wayland Architecture X vs. Wayland Architecture 理解Wayland架构及其与X的不同之处的一个好方法是跟踪一个事件从输入设备到它在屏幕上产生影响的点的过程。 这是我们现在在X中的情况&#xff1a; 内核从输入设备获取事件&…

物联网水位计集成GPS

在物联网&#xff08;IoT&#xff09;应用中&#xff0c;将水位计与 GPS&#xff08;全球定位系统&#xff09; 集成&#xff0c;可以为水位监测系统增加地理位置信息&#xff0c;从而提升数据的空间维度和应用价值。以下是集成GPS的水位计的详细功能、优势和应用场景&#xff…

Linux的进程观:简单性如何成就强大性(三)

1. 环境变量 1.1. 基本概念 环境变量(environment variables)⼀般是指在操作系统中⽤来指定操作系统运⾏环境的⼀些参数。 如&#xff1a;我们在编写C/C代码的时候&#xff0c;在链接的时候&#xff0c;从来不知道我们的所链接的动态静态库在哪⾥&#xff0c;但是照样可以链接…