Android學習制作app(ESP8266-01S連接-簡單制作)

一、理論

部分理論見arduino學習-CSDN博客和Android Studio安裝配置_android studio gradle 配置-CSDN博客

以下直接上代碼和效果視頻,esp01S的收發硬件代碼目前沒有分享,但是可以通過另一個手機網絡調試助手進行模擬。也可以直接根據我的代碼進行改動自行使用,代碼中已經對模塊進行了詳細注釋。本人不是java開發專業人士,也是通過ai完成的。

使用以下文件需要完成AndroidStdio的安裝和SDK,SDK插件、gradle的配置,詳細可以見之前的文章。

1、主xml文件制作界面

通過linearlayout布局,制作簡單的界面,app頭部為標題,中間為按鈕和text顯示。

<?xml version="1.0" encoding="utf-8"?>
<!-- CYA開發,SmartOrderDishes內容,VX:18712214828 -->
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity">
<!--    頭部--><LinearLayoutandroid:layout_width="match_parent"android:layout_weight="1"android:layout_height="match_parent"android:gravity="top"android:orientation="horizontal"><TextViewandroid:layout_width="match_parent"android:layout_height="100dp"android:text="SmartOrderDishes"android:background="#609E9245"android:gravity="center|left"android:paddingLeft="30dp"android:textSize="20sp"android:textStyle="bold"android:letterSpacing="0.2"android:drawableStart="@mipmap/ic_launcher"/></LinearLayout>
<!--    顯示模塊--><LinearLayoutandroid:layout_width="match_parent"android:layout_weight="0.5"android:layout_height="match_parent"android:gravity="center"android:orientation="vertical"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"><TextViewandroid:layout_width="400dp"android:layout_height="match_parent"android:text="在連接ESP-01S WIFI后,等待LCD1602顯示CanConnectServer。點擊連接按鈕,連接服務器"android:textSize="20dp"android:gravity="left"/></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"><Buttonandroid:onClick="Connect"android:layout_width="120dp"android:layout_height="60dp"android:layout_marginLeft="10dp"android:text="連接"/><Buttonandroid:onClick="OffConnect"android:layout_width="120dp"android:layout_height="60dp"android:layout_marginLeft="10dp"android:text="斷開連接"/></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:paddingTop="50dp"><TextViewandroid:id="@+id/Show_Text"android:layout_width="wrap_content"android:layout_height="50dp"android:textSize="20sp"android:text="Wait Checking out!"android:gravity="center"/></LinearLayout></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:layout_weight="1"android:gravity="center"android:orientation="horizontal"></LinearLayout>
</LinearLayout>

?2、主xml對應的java文件

此文件中,對socket連接和收發線程進行了使用,并且有兩個按鈕點擊事件,和接收到服務器數據的彈窗和彈窗按鈕點擊事件。

package com.example.smartorderdishes;
/*
CYA開發,VX:18712214828
自動點餐系統安卓app:
1、主線程進行點擊時間和線程偵聽
2、手機連接ESP-01S的WIFI后點擊連接即可連接ESP服務器。(通過8080端口和192.168.4.1默認服務器ip)
3、接收到數據后進行彈窗顯示需要結算的桌面,和總金額。
4、彈窗中點擊確定即可結算。ESP會受到數據包。*/
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";//主java文件TAGprivate SocketClient socketClient;//socket自定義庫文件變量private TextView textView;//TextView標簽變量@SuppressLint("MissingInflatedId")@Overrideprotected void onCreate(Bundle savedInstanceState) {//主java文件函數,只會運行一次super.onCreate(savedInstanceState);EdgeToEdge.enable(this);setContentView(R.layout.activity_main);ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);return insets;});socketClient = new SocketClient(this);//變量對象初始化textView = findViewById(R.id.Show_Text);//獲取標簽id// 設置數據接收回調// 連接成功后啟動持續監聽socketClient.setDataReceivedCallback(new SocketClient.DataReceivedCallback() {@Overridepublic void onDataReceived(String data) {runOnUiThread(() -> {byte[]  DataPacket = socketClient.hexStringToByteArray(data);int deskNum = ((DataPacket[1]&0xF0)/16)+1;int priceCount = (DataPacket[1]*256+DataPacket[2])&0x0FFF;showDialog(data);});}});}// 連接按鈕點擊事件public void Connect(View view) {// 連接到服務器(內部會自動啟動接收循環)socketClient.connectToServer();}//斷開連接按鈕點擊事件public void OffConnect(View view) {// 關閉連接socketClient.closeConnection();}// 顯示彈窗private void showDialog(String data) {AlertDialog.Builder builder = new AlertDialog.Builder(this);//新建彈窗對象byte[]  DataPacket = socketClient.hexStringToByteArray(data);//傳入的數據轉化為字節數組int deskNum = ((DataPacket[1]&0xF0)/16)+1;//桌號獲取int priceCount = (DataPacket[1]*256+DataPacket[2])&0x0FFF;//總金額獲取builder.setTitle("桌號"+deskNum+",結算請求:");//彈窗標題builder.setMessage("共計總金額$" + priceCount+"是否結算!");//彈窗信息// 確定按鈕builder.setPositiveButton("確認結算", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {//確認按鈕點擊事件Toast.makeText(MainActivity.this, "You clicked OK", Toast.LENGTH_SHORT).show();//發送十六進制數據String hexData = "EBAAFF90"; //發送結算成功數據包socketClient.sendHexData(hexData);textView.setText("桌號:" + deskNum+"結算,總金額$"+priceCount+"\n");//顯示/*textView.setText("桌號:" + deskNum+"結算,總金額$"+priceCount+"\n"+"Data:"+data);*/}});// 取消按鈕builder.setNegativeButton("取消結算", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Toast.makeText(MainActivity.this, "You clicked Cancel", Toast.LENGTH_SHORT).show();}});// 顯示彈窗AlertDialog dialog = builder.create();dialog.show();}}

?3、socket連接服務器、偵聽數據包和發送數據包線程,Java文件

package com.example.smartorderdishes;import android.content.Context;
import android.util.Log;
import android.widget.Toast;import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class SocketClient {private static final String SERVER_IP = "192.168.4.1";//連接的指定IPprivate static final int SERVER_PORT = 8080;//連接服務器的指定端口private static final int CONNECTION_TIMEOUT = 5000;//連接超時時間 msprivate static final int READ_TIMEOUT = 5000; // 新增讀取超時時間 msprivate Socket socket;//socket變量private BufferedOutputStream out;//輸出緩沖區變量private BufferedInputStream in;//輸入緩沖區變量private Context context;//private ExecutorService executorService;//單線程 用于連接服務器private ExecutorService receiverExecutor; // 獨立線程池用于接收數據public SocketClient(Context context) {this.context = context;executorService = Executors.newSingleThreadExecutor();//單線程的執行器服務(Executor Service),用于管理和調度任務的執行receiverExecutor = Executors.newSingleThreadExecutor(); // 獨立線程池 線程用于接收數據}// 連接服務器(修改后的代碼)public void connectToServer() {executorService.execute(() -> {//線程提交不需要返回結果的任務try {//異常拋出socket = new Socket();//socket對象socket.connect(new InetSocketAddress(SERVER_IP, SERVER_PORT), CONNECTION_TIMEOUT);//socket連接,指定地址、端口和超時時間socket.setSoTimeout(READ_TIMEOUT); // 設置讀取超時out = new BufferedOutputStream(socket.getOutputStream());//發送緩沖區對象in = new BufferedInputStream(socket.getInputStream());//接收緩沖區對象runOnUiThread(() -> {//runOnUiThread() 是 Activity 類中的一個方法 ,用于在主線程執行代碼Toast.makeText(context, "Connected to server", Toast.LENGTH_SHORT).show();Log.d("SocketClient", "Connected to server");});// 連接成功后啟動接收循環startReceivingData();} catch (IOException e) {runOnUiThread(() -> {Toast.makeText(context, "Failed to connect: " + e.getMessage(), Toast.LENGTH_SHORT).show();Log.e("SocketClient", "Connection error: " + e.getMessage());});}});}// 發送十六進制數據public void sendHexData(String hexData) {executorService.execute(new Runnable() {@Overridepublic void run() {if (out != null && socket != null && !socket.isClosed()) {try {// 將十六進制字符串轉換為字節數組byte[] data = hexStringToByteArray(hexData);out.write(data);//發送字節數組out.flush();//發送完畢后,關閉發送Log.d("SocketClient", "Sent (Hex): " + hexData);} catch (IOException e) {e.printStackTrace();runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(context, "Failed to send data: " + e.getMessage(), Toast.LENGTH_SHORT).show();}});}} else {runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(context, "Not connected to server", Toast.LENGTH_SHORT).show();}});}}});}// 接收數據包(0xEB 0xXX 0xXX 0x90)// 啟動接收循環private void startReceivingData() {receiverExecutor.execute(() -> {//通過單線程執行器,所有提交的任務都會按順序在一個單獨的線程中執行。Log.d("SocketClient", "Starting receive loop");try {while (!Thread.currentThread().isInterrupted()//用于檢查當前線程是否已被中斷的方法&& socket != null//檢查 Socket 對象是否已經被初始化且不為 null。這個檢查通常用于確保在嘗試使用 Socket 進行網絡通信之前,它已經被正確創建和配置。&& !socket.isClosed()//檢查 Socket 對象是否被關閉&& in != null) {//確保輸入流(InputStream)對象已經被正確初始化且不為 null,避免潛在的 NullPointerExceptionbyte[] buffer = new byte[1024];//存儲獲取的數據int bytesRead;//存儲獲取的數據長度try {bytesRead = in.read(buffer); // 阻塞讀取(但設置了超時),返回數組長度if (bytesRead == -1) {//未讀取到數據Log.d("SocketClient", "Connection closed by server");break;}String hexResponse = byteArrayToHexString(buffer, bytesRead);//轉字節數組換為字符串Log.d("SocketClient", "Received (Hex): " + hexResponse);if (isValidDataPacket(buffer, bytesRead)) {//判斷是否符合數據包格式Log.d("SocketClient", "Valid packet received");// 觸發回調if (dataReceivedCallback != null) {//回調接口變量是否為空dataReceivedCallback.onDataReceived(hexResponse);//回調不為空則運行回調函數,回調接收到的hex字符串}}} catch (SocketTimeoutException e) {Log.d("SocketClient", "Read timeout, retrying...");continue;} catch (IOException e) {Log.e("SocketClient", "Read error: " + e.getMessage());break;}}} finally {Log.d("SocketClient", "Exiting receive loop");}});}// 檢查數據包是否符合 0xEB 0xXX 0xXX 0x90 格式private boolean isValidDataPacket(byte[] data, int length) {if (length < 4) {Log.d("SocketClient", "Invalid packet: length < 4");return false;}boolean isValid = (data[0] == (byte) 0xEB) && (data[3] == (byte) 0x90);Log.d("SocketClient", "Data validity: " + isValid);return isValid;}// 關閉連接public void closeConnection() {executorService.execute(new Runnable() {@Overridepublic void run() {try {if (out != null) out.close();if (in != null) in.close();if (socket != null) socket.close();//關閉socket連接Log.d("SocketClient", "Connection closed");} catch (IOException e) {e.printStackTrace();}}});}// 回調接口,用于接收數據/*onDataReceived 是一個常見的回調方法名稱,通常用于在數據接收到時通知監聽器或處理數據。這個方法一般定義在一個接口中,并由實現該接口的類提供具體的數據處理邏輯。*/public interface DataReceivedCallback {void onDataReceived(String data);}// 設置回調接口private DataReceivedCallback dataReceivedCallback;//回調接口變量,回調接口為自定義,在上面已定義public void setDataReceivedCallback(DataReceivedCallback callback) {this.dataReceivedCallback = callback;}// 在主線程中運行代碼private void runOnUiThread(Runnable action) {new android.os.Handler(context.getMainLooper()).post(action);}// 將十六進制字符串轉換為字節數組public byte[] hexStringToByteArray(String hex) {int len = hex.length();byte[] data = new byte[len / 2];for (int i = 0; i < len; i += 2) {data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)+ Character.digit(hex.charAt(i + 1), 16));}return data;}// 將字節數組轉換為十六進制字符串private String byteArrayToHexString(byte[] bytes, int length) {StringBuilder hex = new StringBuilder();for (int i = 0; i < length; i++) {hex.append(String.format("%02X", bytes[i]));}return hex.toString();}}

?

?4、app獲取網絡權限文件,以及啟動文件配置文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><!-- 配置網絡權限 --><!-- 互聯網訪問 --><uses-permission android:name="android.permission.INTERNET" /> <!-- 訪問網絡狀態 --><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 訪問wifi狀態 --><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><!-- 訪問WiFi網絡的信息 --><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><!-- 允許改變WiFi連接狀態(如果需要的話) --><uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /><!-- 從Android 6.0(API level 23)開始,獲取WiFi信息也需要位置權限 --><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><!-- 或者使用粗略的位置權限 --><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.SmartOrderDishes"tools:targetApi="31"><!-- 配置Activity可啟動輸出權限 --><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

二、效果

說明:

1、esp8266-01S開啟AP模式的多連接的Station模式。設定端口為8080,默認ip應該是192.168.4.1,網絡SSID(名稱)為ESP-01S。這些里面目前是固定的,配置即ESP8266作為熱點和服務器,手機連接ESP8266的WIFI,然后作為客戶端手機連接到ESP8266的服務器,進行通信

2、手機連接ESP8266的wifi后。等待配置完畢,然后進行服務器連接,連接完成手機會有信息提醒。

3、連接完成后,esp8266給手機發送0xEB 0xXX 0xXX 0x90的數據包DATA[4](下標從0開始),其中DATA[1]的高4bit作為桌位,低12bit為總金額。

4、接收到數據后手機app進行彈窗,點擊確定后手機app界面text改變。并且向ESP8266發送EBAAFF90(HEX)數據作為結賬完成的標志數據包。

效果視頻

智能點餐系統開發視頻

?

代碼詳解?

?

?

?

其他代碼問題(個人理解):

首先執行主線程mainactivity.java內容,創建UI和監聽按鈕動作。在onCreate創建的生命周期

(只執行一次,設置了數據接收回調的動作內容)。在socketclient.java中定義了回調函數,數據發送函數,數據接收函數,數據處理函數,類對象線程池創建等。

當mainactivity.java點擊連接按鈕時,觸發Connect方法,進行服務器連接,在socketclient.java中的連接方法connectToServer啟動了receiverExecutor線程。

receiverExecutor線程有while,會在while內持續運行,當

這些情況,線程才會結束,即意外斷開服務器連接或者手動斷開連接,線程才會退出,如果?in.read(buffer)?沒有數據可讀,線程會阻塞(掛起),直到有數據到達或超時。在接收到正確的數據包時,會觸發回調,會在receiverExecutor運行mainactivity內的程序(想在主線程運行內容需要使用runOnUiThread())。

----------------------------------------------------------------------------------------

看一下AI的回答:

?

?

?

?

?

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/894422.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/894422.shtml
英文地址,請注明出處:http://en.pswp.cn/news/894422.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

圖書管理系統 Axios 源碼__新增圖書

目錄 功能介紹 核心代碼解析 源碼&#xff1a;新增圖書功能 總結 本項目基于 HTML、Bootstrap、JavaScript 和 Axios 開發&#xff0c;實現了圖書的增刪改查功能。以下是新增圖書的功能實現&#xff0c;適合前端開發學習和項目實踐。 功能介紹 用戶可以通過 模態框&#xf…

DeepSeek Janus-Pro:多模態AI模型的突破與創新

近年來&#xff0c;人工智能領域取得了顯著的進展&#xff0c;尤其是在多模態模型&#xff08;Multimodal Models&#xff09;方面。多模態模型能夠同時處理和理解文本、圖像等多種類型的數據&#xff0c;極大地擴展了AI的應用場景。DeepSeek(DeepSeek-V3 深度剖析&#xff1a;…

AJAX XML

AJAX XML 引言 隨著互聯網技術的不斷發展,Web應用對用戶交互性和實時性的要求越來越高。AJAX(Asynchronous JavaScript and XML)技術的出現,為Web應用開發提供了強大的支持。AJAX技術允許Web應用在不重新加載整個頁面的情況下,與服務器進行異步通信。XML作為數據傳輸格式…

OpenGL學習筆記(五):Textures 紋理

文章目錄 紋理坐標紋理環繞方式紋理過濾——處理紋理分辨率低的情況多級漸遠紋理Mipmap——處理紋理分辨率高的情況加載與創建紋理 &#xff08; <stb_image.h> &#xff09;生成紋理應用紋理紋理單元練習1練習2練習3練習4 通過上一篇著色部分的學習&#xff0c;我們可以…

代理模式——C++實現

目錄 1. 代理模式簡介 2. 代碼示例 1. 代理模式簡介 代理模式是一種行為型模式。 代理模式的定義&#xff1a;由于某些原因需要給某對象提供一個代理以控制該對象的訪問。這時&#xff0c;訪問對象不適合或者不能直接訪問引用目標對象&#xff0c;代理對象作為訪問對象和目標…

Vue3 表單:全面解析與最佳實踐

Vue3 表單&#xff1a;全面解析與最佳實踐 引言 隨著前端技術的發展&#xff0c;Vue.js 已經成為最受歡迎的前端框架之一。Vue3 作為 Vue.js 的最新版本&#xff0c;帶來了許多改進和新的特性。其中&#xff0c;表單處理是 Vue 應用中不可或缺的一部分。本文將全面解析 Vue3 …

C++11新特性之范圍for循環

1.介紹 C11標準之前&#xff0c;使用for循環遍歷數組或容器&#xff0c;只能使用以下結構&#xff1a; for&#xff08;表達式1&#xff1b;表達式2&#xff1b;表達式3&#xff09;{ 循環體 } 那么在C11標準中&#xff0c;除了上面的方法外&#xff0c;又引入了一種全新的語…

攻防世界 fileclude

代碼審計 WRONG WAY! <?php include("flag.php"); highlight_file(__FILE__);//高亮顯示文件的源代碼 if(isset($_GET["file1"]) && isset($_GET["file2"]))//檢查file1和file2參數是否存在 {$file1 $_GET["file1"];$fi…

圖書管理系統 Axios 源碼__獲取圖書列表

目錄 核心功能 源碼介紹 1. 獲取圖書列表 技術要點 適用人群 本項目是一個基于 HTML Bootstrap JavaScript Axios 開發的圖書管理系統&#xff0c;可用于 添加、編輯、刪除和管理圖書信息&#xff0c;適合前端開發者學習 前端交互設計、Axios 數據請求 以及 Bootstrap 樣…

Vue 響應式渲染 - 列表布局和v-html

Vue 漸進式JavaScript 框架 基于Vue2的學習筆記 - Vue 響應式渲染 - 列表布局和v-html 目錄 列表布局 簡單渲染列表 顯示索引值 點擊變色 V-html 作用 注意 采用策略 應用 總結 列表布局 簡單渲染列表 Data中設置狀態&#xff0c;是一個數組格式的默認信息。 然后…

如何實現一個CLI命令行功能 | python 小知識

如何實現一個CLI命令行功能 | python 小知識 在現代軟件開發中&#xff0c;命令行界面&#xff08;CLI&#xff09;的設計與交互至關重要。Click是一個強大的Python庫&#xff0c;專門用于快速創建命令行界面&#xff0c;以其簡單易用性和豐富的功能贏得了開發者的青睞。本文將…

[SAP ABAP] Debug Skill

SAP ABAP Debug相關資料 [SAP ABAP] DEBUG ABAP程序中的循環語句 [SAP ABAP] 靜態斷點的使用 [SAP ABAP] 在ABAP Debugger調試器中設置斷點 [SAP ABAP] SE11 / SE16N 修改標準表(慎用)

kamailio-Core 說明書 版本:Kamailio SIP Server v6.0.x(穩定版)

Core 說明書 版本&#xff1a;Kamailio SIP Server v6.0.x&#xff08;穩定版&#xff09; 概述 本教程收集了 Kamailio 導出的函數和參數 core 添加到配置文件中。 注意&#xff1a;此頁面上的參數不按字母順序排列。 結構 kamailio.cfg 的結構可以看作是三個部分&#xff…

.Net / C# 繁體中文 與 簡體中文 互相轉換, 支持地方特色詞匯

版本號 Nuget 搜索 “OpenCCNET”, 注意別找錯, 好多庫的名字都差不多 支持 “繁,簡” 的互相轉換, 支持多個地區常用詞匯的轉換, 還支持 日文的新舊轉換. OpenCC 在 .Net 中的實現 https://github.com/CosineG/OpenCC.NET <PackageReference Include"OpenCCNET"…

Redis腦裂問題詳解及解決方案

Redis是一種高性能的內存數據庫&#xff0c;廣泛應用于緩存、消息隊列等場景。然而&#xff0c;在分布式Redis集群中&#xff0c;腦裂問題&#xff08;Split-Brain&#xff09;是一個需要特別關注的復雜問題。本文將詳細介紹Redis腦裂問題的成因、影響及解決方案。 一、什么是…

LLMs之OpenAI o系列:OpenAI o3-mini的簡介、安裝和使用方法、案例應用之詳細攻略

LLMs之OpenAI o系列&#xff1a;OpenAI o3-mini的簡介、安裝和使用方法、案例應用之詳細攻略 目錄 相關文章 LLMs之o3&#xff1a;《Deliberative Alignment: Reasoning Enables Safer Language Models》翻譯與解讀 LLMs之OpenAI o系列&#xff1a;OpenAI o3-mini的簡介、安…

女生年薪12萬,算不算屬于高收入人群

在繁華喧囂的都市中&#xff0c;我們時常會聽到關于收入、高薪與生活質量等話題的討論。尤其是對于年輕女性而言&#xff0c;薪資水平不僅關乎個人價值的體現&#xff0c;更直接影響到生活質量與未來的規劃。那么&#xff0c;女生年薪12萬&#xff0c;是否可以被劃入高收入人群…

AI開發學習之——PyTorch框架

PyTorch 簡介 PyTorch &#xff08;Python torch&#xff09;是由 Facebook AI 研究團隊開發的開源機器學習庫&#xff0c;廣泛應用于深度學習研究和生產。它以動態計算圖和易用性著稱&#xff0c;支持 GPU 加速計算&#xff0c;并提供豐富的工具和模塊。 PyTorch的主要特點 …

Python安居客二手小區數據爬取(2025年)

目錄 2025年安居客二手小區數據爬取觀察目標網頁觀察詳情頁數據準備工作&#xff1a;安裝裝備就像打游戲代碼詳解&#xff1a;每行代碼都是你的小兵完整代碼大放送爬取結果 2025年安居客二手小區數據爬取 這段時間需要爬取安居客二手小區數據&#xff0c;看了一下相關教程基本…

OpenCV:開運算

目錄 1. 簡述 2. 用腐蝕和膨脹實現開運算 2.1 代碼示例 2.2 運行結果 3. 開運算接口 3.1 參數詳解 3.2 代碼示例 3.3 運行結果 4. 開運算應用場景 5. 注意事項 6. 總結 相關閱讀 OpenCV&#xff1a;圖像的腐蝕與膨脹-CSDN博客 OpenCV&#xff1a;閉運算-CSDN博客 …