Android 蓝牙开发( 四 )

前言

上一篇文章给大家分享了Kotlin版的Android蓝牙的基础知识和基础用法,不过上一篇都是一些零散碎片化的程序,,这一篇给大家分享Android蓝牙开发实战项目Kotlin+Compose的初步使用

效果演示 : 

Android Compose 蓝牙开发

Android蓝牙实战开发步骤

1.新建Android项目添加蓝牙权限

下图所示:MyBluetoothDemo为刚刚创建的Android空项目,我们现在清单文件中把我们需要用到的权限声明一下,其中定位权限还需要做动态申请

2.封装BluetoothAdapter类

BluetoothAdapter类提供了常用的蓝牙API,我这里创建了一个BlueToothController类,小编这里是先将这些API封装到了一个BlueToothController类中,方便后续使用和操作

package com.example.bluetoothcomposeimport android.annotation.SuppressLint
import android.app.Activity
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothSocket
import android.content.Context
import android.content.Intentobject BlueToothController {val mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter()/*** 检查设备是否支持蓝牙*/fun isBluetoothSupport(): Boolean {return mBluetoothAdapter !=null}/*** 检查该设备蓝牙是否开启*/@SuppressLint("MissingPermission")fun isBluetoothEnabled(): Boolean {return mBluetoothAdapter.enable()}/*** 打开蓝牙*/@SuppressLint("MissingPermission")fun turnOnBlueTooth(activity: Activity, requestCode: Int) {val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)activity.startActivityForResult(intent, requestCode)}/*** 打开蓝牙可见性*/@SuppressLint("MissingPermission")fun enableVisibily(context: Context) {val intent = Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE)intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300)context.startActivity(intent)}/*** 停止查找设备*/@SuppressLint("MissingPermission")fun cancelFindDevice() {mBluetoothAdapter.cancelDiscovery()}/*** 判断当前设备是否在查找蓝牙设备*/@SuppressLint("MissingPermission")fun isStartDiscovering(): Boolean {return mBluetoothAdapter.isDiscovering}/*** 判断当前设备是否未在查找蓝牙设备*/@SuppressLint("MissingPermission")fun isCancelDiscovering(): Boolean {return !mBluetoothAdapter.isDiscovering}/*** 查找设备*/@SuppressLint("MissingPermission")fun findDevice() {mBluetoothAdapter.startDiscovery()}/*** 获取已绑定设备*/@SuppressLint("MissingPermission")fun getBondedDeviceList(): List<BluetoothDevice?>? {return ArrayList(mBluetoothAdapter.bondedDevices)}/*** 判断蓝牙是否连接*/@SuppressLint("MissingPermission")fun isConnectBlue(bluetoothSocket: BluetoothSocket?): Boolean {return bluetoothSocket != null && bluetoothSocket.isConnected}
}

3. 编写Compose UI页面

这里的UI样式,在后面我给出了完整版的,大家可以去复制一下

MainScreen:这是我们MainActivity的UI,放置了一个Column(竖向布局)和Menu

    @Composablefun MainScreen() {var expanded = remember {mutableStateOf(false)}Column(modifier = Modifier.fillMaxSize()){Row(modifier = Modifier.fillMaxWidth().background(Blue).padding(vertical = 12.dp).height(35.dp),verticalAlignment = Alignment.CenterVertically,horizontalArrangement = Arrangement.Start) {Text(text = "可用设备",modifier = Modifier.weight(1f).offset(10.dp))if(isRefresh.value){CircularProgressIndicator(modifier = Modifier.size(25.dp),color = White)}Box() {Icon(painter = painterResource(id = R.drawable.ic_setting),contentDescription = null,modifier = Modifier.width(50.dp).fillMaxHeight().clickable {expanded.value = true},)if(expanded.value){DropdownMenu(expanded = expanded.value,onDismissRequest = {expanded.value = false}) {data.forEachIndexed{ index: Int, s: String ->DropdownMenuItem(onClick = {when (index) {0 -> {if(BlueToothController.isBluetoothSupport()){Toast.makeText(this@MainActivity,"本机支持蓝牙功能",Toast.LENGTH_SHORT).show()}else{Toast.makeText(this@MainActivity,"本机暂不支持蓝牙功能",Toast.LENGTH_SHORT).show()}}1 -> {if(BlueToothController.isBluetoothEnabled()){Toast.makeText(this@MainActivity,"用户允许开启蓝牙",Toast.LENGTH_SHORT).show()}else{Toast.makeText(this@MainActivity,"用户拒绝开启蓝牙",Toast.LENGTH_SHORT).show()}}2 -> {selected.value = 3Log.d(TAG,"查看已绑定设备")if(BlueToothController.isStartDiscovering()){BlueToothController.cancelFindDevice()}deviceList.clear()for (device in BlueToothController.getBondedDeviceList()!!){deviceList.add(device!!)}}3 -> {if(BlueToothController.isStartDiscovering()){Log.d(TAG,"停止查找")BlueToothController.cancelFindDevice()deviceList!!.clear()}selected.value = 4BlueToothController.findDevice()Log.d(TAG,"开始查找")}}Log.d(TAG,selected.value.toString())expanded.value = false}) {Text(text = s)}}}}}}DeviceListView()}if(openDialog.value){AlterDialog()}}

AlterDialog:    用来显示弹窗

    @Composablefun AlterDialog() {AlertDialog(onDismissRequest = { openDialog.value = false },title = { Text(text = text.value) },text = {Text(text = "0c 11 09 41 23 00 01 03 FF")}, confirmButton = {TextButton(onClick = {openDialog.value = falsesendMessage()}) {Text(text = "发送")}}, dismissButton = {TextButton(onClick = { openDialog.value = false }) {Text(text = "取消")}})}

DeviceListView: 这是一个列表控件,相当于RecycleView  

@Composablefun DeviceListView(){LazyColumn(Modifier.fillMaxSize(),contentPadding =  PaddingValues(5.dp,1.dp),verticalArrangement = Arrangement.spacedBy(5.dp)){items(deviceList!!.size){ index->ListItem(index, deviceList[index])}}}

ListItem:这是每个LazyColumn中每个列表的UI样式

@Composablefun ListItem(index: Int, blueToothDevice: BluetoothDevice){Card(shape = RoundedCornerShape(4.dp),elevation = 2.dp) {Row(modifier = Modifier.height(50.dp).fillMaxWidth().clickable {openDialog.value = trueif (blueToothDevice.name == null) {text.value = "N/A"} else {text.value = blueToothDevice.name}//Gatt协议连接蓝牙var bluetoothGatt =blueToothDevice.connectGatt(this@MainActivity, true, mGattCallback)bluetoothGatt.connect()Log.d(TAG, "点击了第$index 个item")},verticalAlignment = Alignment.CenterVertically,) {Image(painter = painterResource(R.drawable.ic_blue),contentDescription = null,modifier = Modifier.fillMaxHeight().padding(all = 5.dp))Column(modifier = Modifier.fillMaxWidth()) {if(blueToothDevice.name==null){Text(text = "N/A",fontWeight = FontWeight.Bold)}else{Text(text = blueToothDevice.name,fontWeight = FontWeight.Bold)}Text(text = blueToothDevice.address,)}}}}

4. 蓝牙搜索,配对,连接,通信

小编这里为了让大家方便,便将搜索,配对,连接都写在了MainActivity中了,Compose UI也在这里了,大家可以复制直接去运行

package com.example.bluetoothcomposeimport android.Manifest.permission.ACCESS_COARSE_LOCATION
import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.annotation.SuppressLint
import android.bluetooth.*
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.content.PermissionChecker.PERMISSION_GRANTED
import com.example.bluetoothcompose.ui.theme.Blue
import com.example.bluetoothcompose.ui.theme.BlueToothComposeTheme
import com.example.bluetoothcompose.ui.theme.White
import java.util.*class MainActivity : ComponentActivity() {private val TAG = "yf"private var deviceList = mutableStateListOf<BluetoothDevice>()private var data = mutableListOf("检查设备是否支持蓝牙","检查设备是否开启蓝牙","查看已配过的蓝牙设备","查找蓝牙设备")var selected = mutableStateOf(0)var openDialog = mutableStateOf(false)var text = mutableStateOf("")var mGatt: BluetoothGatt? = nullvar mWriter: BluetoothGattCharacteristic? = nullprivate var isRefresh = mutableStateOf(false)override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {BlueToothComposeTheme {// A surface container using the 'background' color from the themeSurface(modifier = Modifier.fillMaxSize(),color = MaterialTheme.colors.background) {MainScreen()}}}}override fun onStart() {super.onStart()isPermission()registerBluetoothReceiver()}//处理找到蓝牙设备和搜索完成的广播消息var receiver: BroadcastReceiver = object : BroadcastReceiver() {@SuppressLint("MissingPermission")override fun onReceive(context: Context, intent: Intent) {val action = intent.action//开始查找设备when {BluetoothAdapter.ACTION_DISCOVERY_STARTED == action -> {//开始搜索if(deviceList!=null){deviceList!!.clear()}isRefresh.value = true}BluetoothDevice.ACTION_FOUND == action -> {//搜到蓝牙设备val device =intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)//把搜索到的设备添加到已找到列表中,显示它的信息deviceList?.add(device!!)Log.d(TAG,"找到了: ${deviceList.size}")}BluetoothAdapter.ACTION_DISCOVERY_FINISHED == action -> {//搜索完毕isRefresh.value = falsewhen (selected.value) {3 -> {}4 -> {Toast.makeText(this@MainActivity,"选择要配对的蓝牙设备",Toast.LENGTH_SHORT).show()}}}BluetoothDevice.ACTION_BOND_STATE_CHANGED == action -> {val device =intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)if (device == null) {Toast.makeText(this@MainActivity,"无设备",Toast.LENGTH_SHORT).show()return}val state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 0)when (state) {BluetoothDevice.BOND_BONDED -> {Toast.makeText(this@MainActivity,"已配对",Toast.LENGTH_SHORT).show()}BluetoothDevice.BOND_BONDING -> {Toast.makeText(this@MainActivity,"正在配对",Toast.LENGTH_SHORT).show()}BluetoothDevice.BOND_NONE -> {Toast.makeText(this@MainActivity,"未配对",Toast.LENGTH_SHORT).show()}}}}}}//动态获取位置权限@SuppressLint("WrongConstant")private fun isPermission() {if (checkSelfPermission(ACCESS_COARSE_LOCATION) !== PERMISSION_GRANTED|| checkSelfPermission(ACCESS_FINE_LOCATION) !== PERMISSION_GRANTED) {requestPermissions(arrayOf(ACCESS_COARSE_LOCATION,ACCESS_FINE_LOCATION), 200)}}private fun registerBluetoothReceiver() {//filter注册广播接收器val filter = IntentFilter()//蓝牙当前状态filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED)//开始扫描蓝牙设备广播filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED)//找到蓝牙设备广播filter.addAction(BluetoothDevice.ACTION_FOUND)//扫描蓝牙设备结束广播filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)//蓝牙设备配对状态改变广播filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED)//设备扫描模式改变广播filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED)registerReceiver(receiver, filter)}@SuppressLint("MissingPermission")@Composablefun MainScreen() {var expanded = remember {mutableStateOf(false)}Column(modifier = Modifier.fillMaxSize()){Row(modifier = Modifier.fillMaxWidth().background(Blue).padding(vertical = 12.dp).height(35.dp),verticalAlignment = Alignment.CenterVertically,horizontalArrangement = Arrangement.Start) {Text(text = "可用设备",modifier = Modifier.weight(1f).offset(10.dp))if(isRefresh.value){CircularProgressIndicator(modifier = Modifier.size(25.dp),color = White)}Box() {Icon(painter = painterResource(id = R.drawable.ic_setting),contentDescription = null,modifier = Modifier.width(50.dp).fillMaxHeight().clickable {expanded.value = true},)if(expanded.value){DropdownMenu(expanded = expanded.value,onDismissRequest = {expanded.value = false}) {data.forEachIndexed{ index: Int, s: String ->DropdownMenuItem(onClick = {when (index) {0 -> {if(BlueToothController.isBluetoothSupport()){Toast.makeText(this@MainActivity,"本机支持蓝牙功能",Toast.LENGTH_SHORT).show()}else{Toast.makeText(this@MainActivity,"本机暂不支持蓝牙功能",Toast.LENGTH_SHORT).show()}}1 -> {if(BlueToothController.isBluetoothEnabled()){Toast.makeText(this@MainActivity,"用户允许开启蓝牙",Toast.LENGTH_SHORT).show()}else{Toast.makeText(this@MainActivity,"用户拒绝开启蓝牙",Toast.LENGTH_SHORT).show()}}2 -> {selected.value = 3Log.d(TAG,"查看已绑定设备")if(BlueToothController.isStartDiscovering()){BlueToothController.cancelFindDevice()}deviceList.clear()for (device in BlueToothController.getBondedDeviceList()!!){deviceList.add(device!!)}}3 -> {if(BlueToothController.isStartDiscovering()){Log.d(TAG,"停止查找")BlueToothController.cancelFindDevice()deviceList!!.clear()}selected.value = 4BlueToothController.findDevice()Log.d(TAG,"开始查找")}}Log.d(TAG,selected.value.toString())expanded.value = false}) {Text(text = s)}}}}}}DeviceListView()}if(openDialog.value){AlterDialog()}}@Preview(showBackground = true,group = "Group1",)@Composablefun DefaultPreview() {MainScreen()}@SuppressLint("MissingPermission")@Composablefun DeviceListView(){LazyColumn(Modifier.fillMaxSize(),contentPadding =  PaddingValues(5.dp,1.dp),verticalArrangement = Arrangement.spacedBy(5.dp)){items(deviceList!!.size){ index->ListItem(index, deviceList[index])}}}@SuppressLint("MissingPermission")@Composablefun ListItem(index: Int, blueToothDevice: BluetoothDevice){Card(shape = RoundedCornerShape(4.dp),elevation = 2.dp) {Row(modifier = Modifier.height(50.dp).fillMaxWidth().clickable {openDialog.value = trueif (blueToothDevice.name == null) {text.value = "N/A"} else {text.value = blueToothDevice.name}//Gatt协议连接蓝牙var bluetoothGatt =blueToothDevice.connectGatt(this@MainActivity, true, mGattCallback)bluetoothGatt.connect()Log.d(TAG, "点击了第$index 个item")},verticalAlignment = Alignment.CenterVertically,) {Image(painter = painterResource(R.drawable.ic_blue),contentDescription = null,modifier = Modifier.fillMaxHeight().padding(all = 5.dp))Column(modifier = Modifier.fillMaxWidth()) {if(blueToothDevice.name==null){Text(text = "N/A",fontWeight = FontWeight.Bold)}else{Text(text = blueToothDevice.name,fontWeight = FontWeight.Bold)}Text(text = blueToothDevice.address,)}}}}@SuppressLint("MissingPermission")@Composablefun AlterDialog() {AlertDialog(onDismissRequest = { openDialog.value = false },title = { Text(text = text.value) },text = {Text(text = "0c 11 09 41 23 00 01 03 FF")}, confirmButton = {TextButton(onClick = {openDialog.value = falsesendMessage()}) {Text(text = "发送")}}, dismissButton = {TextButton(onClick = { openDialog.value = false }) {Text(text = "取消")}})}private val mGattCallback: BluetoothGattCallback = object : BluetoothGattCallback() {@SuppressLint("MissingPermission")override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {//连接成功if (newState == BluetoothProfile.STATE_CONNECTED) {//进行服务发现gatt.discoverServices()Log.d(TAG, "连接成功")} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {//连接断开,处理断开逻辑Log.d(TAG, "连接断开")}}@SuppressLint("MissingPermission")override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {Log.d(TAG, "onServicesDiscovered : $status ==>> $gatt")//发现服务成功,处理服务和特征值if (status == BluetoothGatt.GATT_SUCCESS) {//发送消息mGatt = gattval service =gatt.getService(UUID.fromString("0000180a-0000-1000-8000-00805F9B34FB"))mWriter =service.getCharacteristic(UUID.fromString("00002ad9-0000-1000-8000-00805F9B34FB"))//打开消息通知mGatt!!.setCharacteristicNotification(mWriter, true)val descriptor: BluetoothGattDescriptor =mWriter!!.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"))descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUEmGatt!!.writeDescriptor(descriptor)} else {Log.d(TAG, "发现服务失败")}}override fun onCharacteristicRead(gatt: BluetoothGatt,characteristic: BluetoothGattCharacteristic,status: Int) {Log.e(TAG, "onCharacteristicRead $status")//读取特征成功,处理特征值if (status == BluetoothGatt.GATT_SUCCESS) {}}override fun onCharacteristicWrite(gatt: BluetoothGatt,characteristic: BluetoothGattCharacteristic,status: Int) {Log.e(TAG, "onCharacteristicWrite $status")//写入特征成功if (status == BluetoothGatt.GATT_SUCCESS) {Log.d(TAG, "发送成功")} else {Log.d(TAG, "发送失败")}}override fun onCharacteristicChanged(gatt: BluetoothGatt,characteristic: BluetoothGattCharacteristic) {//接收到数据val data = characteristic.value//处理接收到的数据Log.d(TAG, "Received data: " + bytesToHexFun2(data))}override fun onDescriptorRead(gatt: BluetoothGatt,descriptor: BluetoothGattDescriptor,status: Int) {super.onDescriptorRead(gatt, descriptor, status)}override fun onDescriptorWrite(gatt: BluetoothGatt,descriptor: BluetoothGattDescriptor,status: Int) {super.onDescriptorWrite(gatt, descriptor, status)}override fun onReliableWriteCompleted(gatt: BluetoothGatt, status: Int) {super.onReliableWriteCompleted(gatt, status)}override fun onReadRemoteRssi(gatt: BluetoothGatt, rssi: Int, status: Int) {super.onReadRemoteRssi(gatt, rssi, status)}override fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) {super.onMtuChanged(gatt, mtu, status)}override fun onServiceChanged(gatt: BluetoothGatt) {super.onServiceChanged(gatt)}override fun onPhyUpdate(gatt: BluetoothGatt, txPhy: Int, rxPhy: Int, status: Int) {super.onPhyUpdate(gatt, txPhy, rxPhy, status)}override fun onPhyRead(gatt: BluetoothGatt, txPhy: Int, rxPhy: Int, status: Int) {super.onPhyRead(gatt, txPhy, rxPhy, status)}}private fun bytesToHexFun2(bytes: ByteArray): String? {var result = 0for (i in bytes.indices) {result += bytes[i]}return byte2Hex((result.inv() and 0xFF).toByte())}fun byte2Hex(inByte: Byte?): String //1字节转2个Hex字符{return String.format("%02x", inByte).toUpperCase()}@SuppressLint("MissingPermission")fun sendMessage(){if (null == mWriter) {Log.e("yf123", "ble:发送失败:null == writer !!!!")} else {mWriter!!.value = byteArrayOf(0x0c.toByte(),0x11.toByte(),0x09.toByte(),0x41.toByte(),0x23.toByte(),0x00.toByte(),0x01.toByte(),0x03.toByte(),0xFF.toByte())mGatt!!.writeCharacteristic(mWriter)}}}

到此为止,我们的程序就到这里了,蓝牙搜索,配对,连接,通信便已经成功实现了,大家可以把代码copy一下拿去运行,具体效果演示图在文章最上方,大家还想了解更多关于Android蓝牙开发的可以继续看我下一篇给大家的分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/116697.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Sqoop实操案例-互联网招聘数据迁移

&#x1f947;&#x1f947;【大数据学习记录篇】-持续更新中~&#x1f947;&#x1f947; 个人主页&#xff1a;beixi 本文章收录于专栏&#xff08;点击传送&#xff09;&#xff1a;【大数据学习】 &#x1f493;&#x1f493;持续更新中&#xff0c;感谢各位前辈朋友们支持…

【实操干货】如何开始用Qt Widgets编程?(四)

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 在本文中&#xff0…

Android 蓝牙开发( 二 )

前言 上一篇文章给大家分享了Android蓝牙的基础知识和基础用法&#xff0c;不过上一篇都是一些零散碎片化的程序&#xff0c;这一篇给大家分享Android蓝牙开发实战项目的初步使用 效果演示 : Android蓝牙搜索&#xff0c;配对&#xff0c;连接&#xff0c;通信 Android蓝牙实…

数据分析师职业发展道路,工作内容是什么?

很多同学问&#xff0c;参加数据分析就业班后之的就业发展道路是怎样的&#xff0c;工作又能做什么呢&#xff1f; 市面上的常见的工作类型有有运营类、技术类及分析类等&#xff0c;可以根据自己的意愿去做适合自己的工作&#xff0c;但是任何工作其实都是需要一技之长。…

基于实例的学习方法

基于实例的学习方法 动机基本概念基于实例的学习基于实例的概念表示 1. 最近邻最近邻的例子理论结果最近邻&#xff08;1- NN&#xff09;:解释问题 K-近邻(KNN)KNN讨论1 &#xff1a;距离度量KNN 讨论2&#xff1a;属性KNN:属性归一化KNN:属性加权 KNN讨论3:连续取值目标函数K…

ssh常用操作

ssh常用操作 SSH是一种安全协议&#xff0c;ssh是该协议的客户端程序&#xff0c;openssh-server则是该协议的服务端程序 常用系统都自带了ssh客户端程序&#xff0c;服务端程序则可能要安装 密码远程登陆 前提&#xff1a;服务器安装了openssh-server&#xff0c;未安装时…

自定义TimeLine实现卡拉OK轨

系列文章目录 自定义TimeLine 自定义TimeLine 系列文章目录前言正文UI部分代码部分Data&#xff08;数据&#xff09;Clip&#xff08;片段&#xff09;Track&#xff08;轨道&#xff09;Mixer&#xff08;混合&#xff09;被控制物体 总结 前言 自定义TimeLine实际上就是自定…

Android安卓webview,网页端生成安卓项目(极速生成)教程

Android安卓webview&#xff0c;网页端生成安卓项目&#xff08;极速生成&#xff09;教程 一&#xff0c;前言 当自己做了一个PC端的页面&#xff0c;也就是前端的页面&#xff0c;或者已经上服的页面&#xff0c;但也想生成一个安卓端供用户使用&#xff0c;本教程详细讲解…

人员位置管理,点亮矿山安全之路

矿山作为一个高危行业&#xff0c;安全问题一直备受关注。人员定位置管理是现代矿山安全管理的重要一环&#xff0c;可以帮助企业更好地实现对人员的实时监控和管理。因此&#xff0c;矿山人员位置管理系统对于矿山安全生产和管理非常重要&#xff0c;可以帮助减少安全事故的发…

BEVFusion复现 (Ubuntu RTX3090)

https://github.com/ADLab-AutoDrive/BEVFusion 1.环境安装 我的机器是RTX3090&#xff0c;CUDA11.1 1.创建虚拟环境 conda create -n bevfusion python3.8.3 2.安装PyTorch 和 torchvision pip install torch1.8.0cu111 torchvision0.9.0cu111 torchaudio0.8.0 -f https://…

Java中的动态代理(JDK Proxy VS CGLib)

前言 动态代理可以说是Java基础中一个比较重要的内容&#xff0c;这块内容关系到Spring框架中的AOP实现原理&#xff0c;所以特别写了一篇作为个人对这块知识的总结。这部分内容主要包括&#xff1a;JDK Proxy和CGLib的基本介绍、二者的实现原理、代码示例等。 什么是动态代理…

C# 如何将使用的Dll嵌入到.exe应用程序中?

文章目录 前言详细实操简要步骤 前言 有没有想自己开发的exe保留一点神秘&#xff0c;不想让他人知道软件使用了哪些dll; 又或许是客户觉得一个软件里面的dll文件太多了&#xff0c;能不能简单一点&#xff0c;直接双击.exe就可以直接运行了&#xff0c;别搞那么多乱七八糟的。…

Three.js相机参数及Z-Fighting问题的解决方案

本主题讨论透视相机以及如何为远距离环境设置合适的视锥体。 推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 透视相机是一种投影模式&#xff0c;旨在模仿人类在现实世界中看待事物的方式。 这是渲染 3D 场景最常用的投影模式。 - three.js 如果你看一下 Three.js 文档…

优思学院|六西格玛中的概率分布有哪些?

为什么概率分布重要&#xff1f; 概率分布是统计学中一个重要的概念&#xff0c;它帮助我们理解随机变量的分布情况以及与之相关的概率。在面对具体问题时&#xff0c;了解概率分布可以帮助我们选择适当的检验或分析策略&#xff0c;以解决问题并做出合理的决策。 常见的概率…

【二】kubernetes master单节点拓展为集群

#服务器 #部署 #云原生 #k8s 一、 前言 一、ubuntu20.04上搭建containerd版&#xff08; 1.2.4 以上&#xff09;k8s及kuboard V3 接上文中&#xff0c;我们已经部署好了单节点master的k8s集群&#xff0c;在生产环境中&#xff0c;单节点的master肯定是不行的&#xff0c;那…

科技探究之旅--亲子研学活动

2023年8月26日&#xff0c;广州市从化区齐家社会工作服务中心&#xff08;以下简称“齐家”&#xff09;的“星乐园-乡村儿童公益辅导服务项目”组织了新开村及西湖村助学点24对亲子到广州市白云区文搏3D打印基地进行“科技探究之旅--亲子研学”活动&#xff0c;旨在发现、点燃…

用Go编写ChatGPT插件

ChatGPT插件平台有望成为影响深远的"下一件大事"&#xff0c;因此对于开发者来说&#xff0c;有必要对ChatGPT插件的开发有一定的了解。原文: Writing a ChatGPT Plugin With Go[1] 我工作的附带福利之一是偶尔可以接触试用一些很酷的新技术&#xff0c;最近的一项技…

实战:基于卷积的MNIST手写体分类

前面实现了基于多层感知机的MNIST手写体识别&#xff0c;本章将实现以卷积神经网络完成的MNIST手写体识别。 1. 数据的准备 在本例中&#xff0c;依旧使用MNIST数据集&#xff0c;对这个数据集的数据和标签介绍&#xff0c;前面的章节已详细说明过了&#xff0c;相对于前面章…

控制goroutine 的并发执行数量

goroutine的数量上限是1048575吗&#xff1f; 正常项目&#xff0c;协程数量超过十万就需要引起重视。如果有上百万goroutine&#xff0c;一般是有问题的。 但并不是说协程数量的上限是100多w 1048575的来自类似如下的demo代码: package mainimport ( "fmt" "ma…

MySQL的mysql-bin.00xx binlog日志文件的清理

目录 引言手工清理配置自动清理 引言 公司一个项目生产环境mysql数据盘占用空间增长得特别快&#xff0c;经过排查发现是开启了mysql的binlog日志。如果把binlog日志关闭&#xff0c;如果操作万一出现问题&#xff0c;就没有办法恢复数据&#xff0c;很不安全&#xff0c;只能…