Android 蓝牙开发( 二 )

前言

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

效果演示 : 

Android蓝牙搜索,配对,连接,通信

Android蓝牙实战开发步骤

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

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

2.封装BluetoothAdapter类

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

package com.example.mybluetoothdemo;import 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.Intent;import java.util.ArrayList;
import java.util.List;public class BlueToothController {private BluetoothAdapter mBluetoothAdapter;public BlueToothController(){//初始化蓝牙适配器mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();}public BluetoothAdapter getBluetoothAdapter() {return mBluetoothAdapter;}/*** 检查设备是否支持蓝牙*/public boolean isBluetoothSupport(){if(mBluetoothAdapter == null){return false;}else {return true;}}/*** 检查该设备蓝牙是否开启*/public boolean isBluetoothEnabled(){if(mBluetoothAdapter.isEnabled()){return true;}else {return false;}}/*** 打开蓝牙*/@SuppressLint("MissingPermission")public void turnOnBlueTooth(Activity activity, int requestCode) {Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);activity.startActivityForResult(intent, requestCode);}/*** 打开蓝牙可见性*/@SuppressLint("MissingPermission")public void enableVisibily(Context context){Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300);context.startActivity(intent);}/*** 停止查找设备*/@SuppressLint("MissingPermission")public void cancelFindDevice(){mBluetoothAdapter.cancelDiscovery();}/*** 判断当前设备是否在查找蓝牙设备*/@SuppressLint("MissingPermission")public boolean isStartDiscovering(){if(mBluetoothAdapter.isDiscovering()){return true;}else {return false;}}/*** 判断当前设备是否未在查找蓝牙设备*/@SuppressLint("MissingPermission")public boolean isCancelDiscovering(){if(!mBluetoothAdapter.isDiscovering()){return true;}else {return false;}}/*** 查找设备*/@SuppressLint("MissingPermission")public void findDevice() {mBluetoothAdapter.startDiscovery();}/*** 获取已绑定设备*/@SuppressLint("MissingPermission")public List<BluetoothDevice> getBondedDeviceList(){return new ArrayList<>(mBluetoothAdapter.getBondedDevices());}/*** 判断蓝牙是否连接*/@SuppressLint("MissingPermission")public boolean isConnectBlue(BluetoothSocket bluetoothSocket){return bluetoothSocket !=null && bluetoothSocket.isConnected();}
}

3. 编写UI页面

activity_main.xml:这是我们MainActivity的UI,放置了一个ListView和一个按钮,ListView用来显示搜索到的蓝牙设备和已配对的蓝牙设备,Button控件用来与连接后的设备发送信息时使用

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingLeft="16.dp"android:paddingRight="16.dp"android:paddingBottom="16.dp"><ListViewandroid:id="@+id/device_list"android:layout_width="match_parent"android:layout_height="match_parent"android:divider="#e90423"android:dividerHeight="1px"></ListView><Buttonandroid:id="@+id/btn_write_1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_alignParentBottom="true"android:text="发送消息"/></RelativeLayout>

既然有了ListView,那就一定有ListView的每条子元素UI,新建list_item.xml

list_item.xml:    用来显示ListView列表的子内容

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:orientation="horizontal"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextView android:id="@+id/text1"android:layout_width="match_parent"android:layout_height="wrap_content"android:textStyle="bold"android:textSize="18sp"/><TextView android:id="@+id/text3"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="13sp"/></LinearLayout></LinearLayout>

然后,我们再为页面右上角写一个menu列表按钮,新建menu_main.xml

menu_main.xml:  

<menu xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"tools:context=".MainActivity" ><itemandroid:id="@+id/is_bluetooth_support"android:title="@string/is_bluetooth_support"android:orderInCategory="1" /><itemandroid:id="@+id/is_bluetooth_enabled"android:title="@string/is_bluetooth_enabled"android:orderInCategory="2" /><itemandroid:id="@+id/bonded_device"android:title="@string/bonded_device"android:orderInCategory="2" /><itemandroid:id="@+id/find_device"android:title="@string/find_device"android:orderInCategory="3" /></menu>

最后,再为大家分享一下string.xml字符串配置信息

4. 蓝牙列表适配器

创建DeviceAdapter类,具体如下图所示:

package com.example.mybluetoothdemo;import android.annotation.SuppressLint;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;import java.util.List;public class DeviceAdapter extends BaseAdapter{private List<BluetoothDevice> mData;private Context mContext;public DeviceAdapter(List<BluetoothDevice> data, Context context){mData = data;mContext = context.getApplicationContext();}@Overridepublic int getCount() {return mData.size();}@Overridepublic Object getItem(int i) {return mData.get(i);}@Overridepublic long getItemId(int i) {return i;}@SuppressLint("MissingPermission")@Overridepublic View getView(int i, View view, ViewGroup viewGroup) {View itemView = view;//复用view,优化性能if(itemView == null){itemView = LayoutInflater.from(mContext).inflate(R.layout.list_item, viewGroup,false);}TextView text1 = itemView.findViewById(R.id.text1);TextView text2 = itemView.findViewById(R.id.text3);text1.setTextColor(Color.BLACK);text2.setTextColor(Color.BLACK);//获取对应的蓝牙设备BluetoothDevice device = (BluetoothDevice) getItem(i);//显示设备名称if(device.getName()==null){text1.setText("N/A");}else {text1.setText(device.getName());}//显示设备地址text2.setText(device.getAddress());return itemView;}//刷新列表,防止搜索结果重复出现public void refresh(List<BluetoothDevice> data){mData = data;notifyDataSetChanged();}}

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

小编这里为了让大家方便,便将搜索,配对,连接都写在了MainActivity中了

package com.example.mybluetoothdemo;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;import android.Manifest;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;import java.util.ArrayList;
import java.util.List;
import java.util.UUID;public class MainActivity extends AppCompatActivity {private final String TAG = "yf";private BlueToothController blueToothController = new BlueToothController();private static final int REQUEST_ENABLE_BT = 1;private ListView listView;private DeviceAdapter blueToothDeviceAdapter,bondBlueToothDeviceAdapter;private List<BluetoothDevice> deviceList = new ArrayList<>();private List<BluetoothDevice> bondedDeviceList = new ArrayList<>();private BluetoothDevice device;private BluetoothGatt bluetoothGatt;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initUI();//判断是否有访问位置的权限,没有权限,直接申请位置权限isPermission();registerBluetoothReceiver();}@SuppressLint("MissingPermission")private void initUI(){listView = findViewById(R.id.device_list);blueToothDeviceAdapter = new DeviceAdapter(deviceList,this);bondBlueToothDeviceAdapter = new DeviceAdapter(bondedDeviceList,this);findViewById(R.id.btn_write_1).setOnClickListener(view -> {if (null == mWriter){Log.e("cx12345","ble:发送失败:null == writer !!!!");}else {mWriter.setValue(new byte[]{(byte)0x0c,(byte)0x11,(byte)0x09,(byte)0x41,(byte)0x23,(byte)0x00,(byte)0x01,(byte)0x03,(byte)0xFF});mGatt.writeCharacteristic(mWriter);}});}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.menu_main,menu);return true;}@SuppressLint("MissingPermission")@Overridepublic boolean onOptionsItemSelected(MenuItem item) {int id = item.getItemId();switch (id){case R.id.is_bluetooth_support:if (blueToothController.isBluetoothSupport()){Toast.makeText(MainActivity.this, "该设备支持蓝牙功能", Toast.LENGTH_SHORT).show();}else {Toast.makeText(MainActivity.this, "该设备不支持蓝牙功能", Toast.LENGTH_SHORT).show();}break;case R.id.is_bluetooth_enabled:if (blueToothController.isBluetoothEnabled()){Toast.makeText(MainActivity.this, "蓝牙已开启", Toast.LENGTH_SHORT).show();}else {blueToothController.turnOnBlueTooth(this,REQUEST_ENABLE_BT);}break;case R.id.bonded_device:setTitle("已配对的设备");bondedDeviceList = blueToothController.getBondedDeviceList();listView.setAdapter(bondBlueToothDeviceAdapter);bondBlueToothDeviceAdapter.refresh(bondedDeviceList);break;case R.id.find_device:setTitle("可用设备");if(blueToothController.isStartDiscovering()){blueToothController.cancelFindDevice();}blueToothController.findDevice();
//                blueToothController.getBluetoothAdapter().startLeScan(leScanCallback);listView.setAdapter(blueToothDeviceAdapter);blueToothDeviceAdapter.refresh(deviceList);listView.setOnItemClickListener(deviceBluetooth);break;default:break;}return super.onOptionsItemSelected(item);}private AdapterView.OnItemClickListener deviceBluetooth = new AdapterView.OnItemClickListener() {@SuppressLint("MissingPermission")public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {device = deviceList.get(i);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//蓝牙绑定
//                device.createBond();//Gatt协议连接蓝牙bluetoothGatt = device.connectGatt(MainActivity.this,true,mGattCallback);bluetoothGatt.connect();}}};//动态获取位置权限private void isPermission(){if ((checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)|| (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 200);}}@SuppressLint("MissingPermission")@Overrideprotected void onDestroy() {super.onDestroy();// 停止设备搜索blueToothController.getBluetoothAdapter().cancelDiscovery();//注销广播unregisterReceiver(receiver);}private void registerBluetoothReceiver(){//filter注册广播接收器IntentFilter filter = new 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);}//处理找到蓝牙设备和搜索完成的广播消息BroadcastReceiver receiver = new BroadcastReceiver() {@SuppressLint("MissingPermission")@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();//开始查找设备if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)){//初始化适配器列表deviceList.clear();bondedDeviceList.clear();blueToothDeviceAdapter.refresh(deviceList);bondBlueToothDeviceAdapter.refresh((bondedDeviceList));}//找到蓝牙设备else if(BluetoothDevice.ACTION_FOUND.equals(action)){//搜到蓝牙设备BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);//把搜索到的设备添加到已找到列表中,显示它的信息deviceList.add(device);blueToothDeviceAdapter.refresh(deviceList);}//查找设备结束else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){//搜索完毕Toast.makeText(MainActivity.this, "选择要配对的蓝牙设备", Toast.LENGTH_SHORT).show();blueToothDeviceAdapter.refresh(deviceList);}//配对状态else if(BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)){BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);if(device == null){Toast.makeText(MainActivity.this, "无设备", Toast.LENGTH_SHORT).show();return;}int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,0);if(state == BluetoothDevice.BOND_BONDED){Toast.makeText(MainActivity.this, "已配对", Toast.LENGTH_SHORT).show();}else if(state == BluetoothDevice.BOND_BONDING){Toast.makeText(MainActivity.this, "正在配对", Toast.LENGTH_SHORT).show();}else if(state == BluetoothDevice.BOND_NONE){Toast.makeText(MainActivity.this, "未配对", Toast.LENGTH_SHORT).show();}}}};private BluetoothGatt mGatt;private BluetoothGattCharacteristic mWriter;/*** @param gatt     返回连接建立的gatt对象* @param status   返回的是此次gatt操作的结果,成功了返回0* @param newState 每次client连接或断开连接状态变化,*                 STATE_CONNECTED 0,*                 STATE_CONNECTING 1,*                 STATE_DISCONNECTED 2,*                 STATE_DISCONNECTING 3*/private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {@SuppressLint("MissingPermission")@Overridepublic void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {//连接成功if(newState == BluetoothProfile.STATE_CONNECTED){//进行服务发现gatt.discoverServices();Log.d(TAG,"连接成功");}else if(newState == BluetoothProfile.STATE_DISCONNECTED){//连接断开,处理断开逻辑Log.d(TAG,"连接断开");}}@SuppressLint("MissingPermission")@Overridepublic void onServicesDiscovered(BluetoothGatt gatt, int status) {Log.d(TAG,"onServicesDiscovered : " + status + " ==>> " + gatt.toString());//发现服务成功,处理服务和特征值if(status == BluetoothGatt.GATT_SUCCESS){//发送消息mGatt = gatt;BluetoothGattService service = gatt.getService(UUID.fromString("0000180a-0000-1000-8000-00805F9B34FB"));mWriter = service.getCharacteristic(UUID.fromString("00002ad9-0000-1000-8000-00805F9B34FB"));//打开消息通知mGatt.setCharacteristicNotification(mWriter,true);BluetoothGattDescriptor descriptor = mWriter.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);mGatt.writeDescriptor(descriptor);}else {Log.d(TAG,"发现服务失败");}}@Overridepublic void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {Log.e(TAG,"onCharacteristicRead " + status);//读取特征成功,处理特征值if(status == BluetoothGatt.GATT_SUCCESS){}}@Overridepublic void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {Log.e(TAG,"onCharacteristicWrite " + status);//写入特征成功if(status == BluetoothGatt.GATT_SUCCESS){Log.d(TAG,"发送成功");}else {Log.d(TAG,"发送失败");}}@Overridepublic void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {//接收到数据byte[] data = characteristic.getValue();//处理接收到的数据Log.d(TAG,"Received data: " + bytesToHexFun2(data));}@Overridepublic void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {super.onDescriptorRead(gatt, descriptor, status);}@Overridepublic void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {super.onDescriptorWrite(gatt, descriptor, status);}@Overridepublic void onReliableWriteCompleted(BluetoothGatt gatt, int status) {super.onReliableWriteCompleted(gatt, status);}@Overridepublic void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {super.onReadRemoteRssi(gatt, rssi, status);}@Overridepublic void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {super.onMtuChanged(gatt, mtu, status);}@Overridepublic void onServiceChanged(@NonNull BluetoothGatt gatt) {super.onServiceChanged(gatt);}@Overridepublic void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {super.onPhyUpdate(gatt, txPhy, rxPhy, status);}@Overridepublic void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {super.onPhyRead(gatt, txPhy, rxPhy, status);}};private char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5','6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};private  String bytesToHexFun2(byte[] bytes) {char[] buf = new char[bytes.length * 2];int index = 0;for(byte b : bytes) { // 利用位运算进行转换,可以看作方法一的变种buf[index++] = HEX_CHAR[b >>> 4 & 0xf];buf[index++] = HEX_CHAR[b & 0xf];}return new String(buf);}}

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

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

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

相关文章

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

很多同学问&#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;只能…

WPF怎么实现文件拖放功能winform怎么实现拖拽功能

WPF怎么实现文件拖放功能winform怎么实现文件拖拽功能&#xff0c;在管理员模式下wpf winform怎么实现文件的拖拽功能 WPF实现文件拖放功能&#xff0c;正常情况并没有什么问题&#xff0c;但是如果你的程序使用管理员身份启动&#xff0c;你就会发现文件拖放功能就会失效。同…

css元素定位:通过元素的标签或者元素的id、class属性定位

前言 大部分人在使用selenium定位元素时&#xff0c;用的是xpath元素定位方式&#xff0c;因为xpath元素定位方式基本能解决定位的需求。xpath元素定位方式更直观&#xff0c;更好理解一些。 css元素定位方式往往被忽略掉了&#xff0c;其实css元素定位方式也有它的价值&…

全新纠错码将量子计算提效10倍!

上周&#xff0c;来自两个研究小组的最新模拟报告称&#xff0c;一类新兴的量子纠错码的效率比目前的“黄金标准”&#xff08;即表面码&#xff09;高出一个数量级。 量子纠错码的工作原理都是将大量容易出错的量子比特转换成更小的“受保护”量子比特&#xff0c;这些量子比特…