flutter bloc 使用詳細解析

源碼地址
flutter_bloc 是基于 BLoC(Business Logic Component)模式的 Flutter 狀態管理庫,它封裝了 bloc package,幫助我們更清晰地組織業務邏輯與 UI 的分離。核心思想是 事件驅動狀態響應


🧠 原理簡介

1. 核心概念

  • Event(事件):用戶的輸入或其他外部觸發,比如按鈕點擊。
  • State(狀態):界面狀態的表現,比如加載中、成功、失敗。
  • Bloc(邏輯組件):接收事件 -> 處理邏輯 -> 發出新狀態。

流程圖如下:

UI → Bloc.add(Event) → Bloc → emit(State) → UI rebuild

🛠? 如何使用

1. 安裝依賴

dependencies:flutter_bloc: ^8.1.3 # 檢查 pub.dev 上的最新版本

2. 創建 Event & State

// counter_event.dart
abstract class CounterEvent {}class Increment extends CounterEvent {}class Decrement extends CounterEvent {}
// counter_state.dart
class CounterState {final int count;CounterState(this.count);
}

3. 創建 Bloc

// counter_bloc.dart
import 'package:flutter_bloc/flutter_bloc.dart';
import 'counter_event.dart';
import 'counter_state.dart';class CounterBloc extends Bloc<CounterEvent, CounterState> {CounterBloc() : super(CounterState(0)) {on<Increment>((event, emit) => emit(CounterState(state.count + 1)));on<Decrement>((event, emit) => emit(CounterState(state.count - 1)));}
}

4. 在 UI 中使用 Bloc

// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'counter_bloc.dart';
import 'counter_event.dart';
import 'counter_state.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {Widget build(BuildContext context) {return BlocProvider(create: (_) => CounterBloc(),child: MaterialApp(home: CounterPage()),);}
}class CounterPage extends StatelessWidget {Widget build(BuildContext context) {final bloc = context.read<CounterBloc>();return Scaffold(appBar: AppBar(title: Text("BLoC Counter")),body: Center(child: BlocBuilder<CounterBloc, CounterState>(builder: (context, state) => Text('Count: ${state.count}', style: TextStyle(fontSize: 30)),),),floatingActionButton: Column(mainAxisAlignment: MainAxisAlignment.end,children: [FloatingActionButton(onPressed: () => bloc.add(Increment()), child: Icon(Icons.add)),SizedBox(height: 10),FloatingActionButton(onPressed: () => bloc.add(Decrement()), child: Icon(Icons.remove)),],),);}
}

? 總結優點

  • UI 和業務邏輯分離,利于測試和維護
  • 明確的事件-狀態流轉,代碼可讀性強
  • 強類型 + 自動重建 UI,適用于中大型項目

和 getx 相比有什么優缺點

flutter_blocGetX 是 Flutter 中兩種常見的狀態管理方案,各有優缺點,適用于不同的場景。下面是二者的詳細對比:


🆚 flutter_bloc vs GetX

維度flutter_blocGetX
設計思想響應式 + 明確事件流轉(事件 -> 狀態)響應式 + 最小 API(簡潔直接)
代碼結構規范、結構清晰(Event / State / Bloc)極簡、靈活(Controller + Observable)
學習曲線中等偏陡,概念較多非常簡單,上手極快
樣板代碼(boilerplate)多,需要定義多個類極少,一個控制器基本搞定
可維護性(大型項目)高,適合多人協作和規范化開發靈活但風險高,依賴命名和使用習慣
社區和文檔強,廣泛用于企業項目,如 Google 官方推薦非官方但很流行,文檔充足
依賴注入(DI)不強制內置,可配合其他包(如 get_it內置自動依賴注入
導航/路由管理依賴其他包(如 go_router自帶強大的路由系統
性能非常高效,基于 Streamemit極高,Reactive 系統 + 最小重建
測試友好性強,適合單元測試/集成測試一般,較多手動控制
異步處理基于事件流程,清晰且易測試支持 Future/async,但自由度高可能導致不規范

? 何時選 flutter_bloc

適合你如果:

  • 需要嚴格分離業務邏輯(企業/團隊協作項目)
  • 希望狀態流轉可追蹤、可測試
  • 項目規模較大或可預期擴展
  • 你熟悉 Redux / Rx 風格編程

? 何時選 GetX

適合你如果:

  • 項目較小或是個人開發
  • 優先快速開發、上手快
  • 喜歡靈活、少寫代碼
  • 同時希望統一路由/DI/狀態/國際化等功能

🏁 舉例對比:計數器

Bloc 實現

bloc.add(Increment()); 
// 多個文件:event.dart, state.dart, bloc.dart

GetX 實現

controller.count++;
// 只要一個 Controller 類,UI 使用 Obx 自動監聽

📌 總結一句話:

Bloc 注重規范和可維護性,適合大型工程;GetX 注重極簡和開發效率,適合快速開發。

BuildContext 上的一些擴展方法

在使用 flutter_bloc(或 provider)時,BuildContext 上的一些擴展方法是關鍵,它們幫助你從上下文中訪問 Bloc、監聽狀態、或者進行條件性重建。

以下是常見的幾種方法的詳細解釋和對比:


? 1. context.read<T>()

功能:

  • 從 widget tree 中 讀取 一個 Bloc(或其他 Provider 提供的對象),不會監聽其狀態變化

用途:

  • 通常用于觸發事件,如 .add(Event),因為不需要監聽。

示例:

context.read<CounterBloc>().add(Increment());

? 2. context.watch<T>()

功能:

  • 讀取并訂閱監聽 Bloc 或狀態變化。
  • 狀態變化會導致 widget rebuild

用途:

  • 通常用于 UI 需要根據 Bloc 狀態實時刷新。

示例:

final state = context.watch<CounterBloc>().state;
return Text('Count: ${state.count}');

? 3. context.select<T, R>(R Function(T value))

功能:

  • 讀取 Bloc(或 Provider)中某個字段的值,并監聽它的變化。
  • 只有當該字段的值發生變化時,才會觸發 rebuild

用途:

  • 精細控制重建,避免無謂的 UI 更新

示例:

final count = context.select<CounterBloc, int>((bloc) => bloc.state.count);
return Text('Count: $count');

? 4. BlocProvider.of<T>(context)

  • 等價于 context.read<T>()
  • 是舊寫法,推薦使用 context.read<T>() 更簡潔。

? 5. BlocBuilder<T, S>

功能:

  • 監聽 Bloc<T> 的狀態 S 并根據狀態變化 rebuild UI。

示例:

BlocBuilder<CounterBloc, CounterState>(builder: (context, state) => Text('Count: ${state.count}'),
);

? 6. BlocListener<T, S>

功能:

  • 用于監聽狀態變化并做一次性副作用操作(如彈窗、跳轉)。

示例:

BlocListener<LoginBloc, LoginState>(listener: (context, state) {if (state is LoginSuccess) {Navigator.pushNamed(context, '/home');}},child: ...
);

? 7. BlocConsumer<T, S>

  • 相當于 BlocBuilder + BlocListener 的組合。
  • 同時用于 build UI 和執行副作用。

🔁 方法使用場景對比表

方法名是否 rebuild是否監聽狀態變化用途
read<T>()??獲取 Bloc 實例、添加事件
watch<T>()??獲取 Bloc 狀態,狀態變就重建
select<T, R>()? (條件)? (某字段變)精細控制重建,提高性能
BlocBuilder??渲染 UI
BlocListener??處理一次性副作用
BlocConsumer??UI 和副作用一起處理

使用場景舉例子

好的,我們用一個異步 API 請求的完整例子來演示 flutter_bloc 中各類常用方法的實際應用,包括:

  • context.read
  • context.watch
  • context.select
  • BlocBuilder
  • BlocListener
  • BlocConsumer

🌐 場景描述:請求用戶信息

模擬從網絡請求一個用戶信息(名字、郵箱),展示加載中、成功、失敗三種狀態。


📦 第一步:定義狀態和事件

// user_event.dart
abstract class UserEvent {}class FetchUser extends UserEvent {}
// user_state.dart
abstract class UserState {}class UserInitial extends UserState {}class UserLoading extends UserState {}class UserLoaded extends UserState {final String name;final String email;UserLoaded({required this.name, required this.email});
}class UserError extends UserState {final String message;UserError(this.message);
}

?? 第二步:創建 UserBloc

// user_bloc.dart
import 'package:flutter_bloc/flutter_bloc.dart';
import 'user_event.dart';
import 'user_state.dart';class UserBloc extends Bloc<UserEvent, UserState> {UserBloc() : super(UserInitial()) {on<FetchUser>((event, emit) async {emit(UserLoading());await Future.delayed(Duration(seconds: 2)); // 模擬網絡延遲try {// 模擬 API 成功返回final name = 'Alice';final email = 'alice@example.com';emit(UserLoaded(name: name, email: email));} catch (e) {emit(UserError('Failed to fetch user'));}});}
}

🖼? 第三步:UI 中使用 Bloc

// user_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'user_bloc.dart';
import 'user_event.dart';
import 'user_state.dart';class UserPage extends StatelessWidget {Widget build(BuildContext context) {return BlocProvider(create: (_) => UserBloc(),child: UserView(),);}
}class UserView extends StatelessWidget {Widget build(BuildContext context) {final bloc = context.read<UserBloc>(); // 獲取 Bloc 實例return Scaffold(appBar: AppBar(title: Text('User Info')),body: BlocConsumer<UserBloc, UserState>(listener: (context, state) {if (state is UserError) {ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(state.message)),);}},builder: (context, state) {if (state is UserInitial) {return Center(child: ElevatedButton(onPressed: () => bloc.add(FetchUser()),child: Text('Load User'),),);} else if (state is UserLoading) {return Center(child: CircularProgressIndicator());} else if (state is UserLoaded) {return Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Text('Name: ${state.name}'),Text('Email: ${state.email}'),],),);} else {return Center(child: Text('Unknown state'));}},),);}
}

🧠 其他方法用法補充

context.watch 示例(只監聽狀態)

final userState = context.watch<UserBloc>().state;
if (userState is UserLoaded) {print(userState.name);
}

context.select 示例(只監聽 name 變化)

final name = context.select<UserBloc, String?>((bloc) {final state = bloc.state;return state is UserLoaded ? state.name : null;
});

? 總結

這個例子完整地展示了:

  • 如何使用 Bloc 組織異步邏輯
  • 如何使用 context.read 觸發事件
  • 如何用 BlocConsumer 分離 UI 構建和副作用(如錯誤提示)
  • 如何用 watch / select 實現更細粒度監聽

## 標題RepositoryProvider

RepositoryProviderflutter_bloc 提供的一個工具類,作用是將“非 Bloc 的對象(如 Repository、Service、API 客戶端)注入到 widget tree 中”,供 Bloc 或其他組件使用。它本質上是一個語義化的 Provider,目的是讓依賴注入更加清晰和語義化。


🧱 1. RepositoryProvider 是什么?

它是 Provider 的語法糖,用于提供數據訪問層(Repository),讓 Bloc 通過依賴注入獲取它。

RepositoryProvider(create: (context) => UserRepository(),child: BlocProvider(create: (context) => UserBloc(context.read<UserRepository>()),child: MyApp(),),
)

🧩 2. 為什么需要 RepositoryProvider?

分離關注點 + 提高可測試性

在 BLoC 架構中,Bloc 只處理業務邏輯,而 Repository 專注于數據來源(數據庫/API/本地緩存等)。

  • 🧼 清晰的依賴層次結構
  • 🔌 可插拔(方便 mock 測試)
  • ?? 依賴共享(避免重復創建對象)

🧪 3. 實戰示例

用戶倉庫

class UserRepository {Future<String> fetchUserName() async {await Future.delayed(Duration(seconds: 1));return 'Alice';}
}

注入層級

void main() {runApp(RepositoryProvider(create: (context) => UserRepository(),child: BlocProvider(create: (context) => UserBloc(context.read<UserRepository>()),child: MyApp(),),),);
}

在 Bloc 中使用

class UserBloc extends Bloc<UserEvent, UserState> {final UserRepository userRepository;UserBloc(this.userRepository) : super(UserInitial()) {on<FetchUser>((event, emit) async {emit(UserLoading());final name = await userRepository.fetchUserName();emit(UserLoaded(name));});}
}

? 4. 優點總結

優點說明
👓 語義清晰明確指出這是 Repository,不是 Bloc
?? 對象共享上層創建、下層 Bloc 可復用
🧪 易測試Bloc 接收參數,可以注入 mock
🧩 解耦結構Bloc 不負責創建數據層

?? 5. 注意事項 / 潛在缺點

缺點或注意點說明
?? 濫用嵌套BlocProvider 和 RepositoryProvider 層級深容易混亂,建議封裝為模塊
?? 生命周期問題如果作用域太小,Bloc 中引用的 Repository 可能會被提前銷毀
?? 多倉庫依賴復雜度提升Bloc 依賴多個 Repository 時,構造函數會變長,可考慮封裝為 Service 層或使用 DI 工具(如 get_it)

📌 何時使用 RepositoryProvider?

? 使用場景:

  • 需要復用或共享 Repository 實例(如網絡請求、數據庫訪問)
  • Bloc 不應該直接創建依賴對象
  • 需要單元測試 Bloc 時方便注入 mock

? 不建議使用場景:

  • 簡單小項目可以直接在 Bloc 中創建對象(僅限臨時用)
  • 對象生命周期不需要跨多個組件

一個多倉庫 + 多 Bloc 的組合使用場景實例

好的,我們來構建一個中型項目的多倉庫 + 多 Bloc + 多 Provider 示例結構,結合 RepositoryProviderBlocProvider,實現高內聚、低耦合的結構設計。


🧱 示例需求:用戶信息 + 設置模塊

有兩個功能模塊:

  1. 用戶模塊(User):從 API 獲取用戶信息
  2. 設置模塊(Settings):管理本地配置(如暗黑模式)

模塊依賴:

模塊依賴內容
UserBloc依賴 UserRepository
SettingsBloc依賴 SettingsRepository

📦 項目結構建議

lib/
├── main.dart
├── repositories/
│   ├── user_repository.dart
│   └── settings_repository.dart
├── blocs/
│   ├── user/
│   │   ├── user_bloc.dart
│   │   ├── user_event.dart
│   │   └── user_state.dart
│   └── settings/
│       ├── settings_bloc.dart
│       ├── settings_event.dart
│       └── settings_state.dart
├── pages/
│   ├── user_page.dart
│   └── settings_page.dart
└── app.dart

1?? Repository 實現

user_repository.dart

class UserRepository {Future<String> fetchUserName() async {await Future.delayed(Duration(seconds: 1));return 'Alice';}
}

settings_repository.dart

class SettingsRepository {bool _darkMode = false;bool get isDarkMode => _darkMode;void toggleDarkMode() => _darkMode = !_darkMode;
}

2?? Bloc 實現(以 User 為例)

user_bloc.dart

class UserBloc extends Bloc<UserEvent, UserState> {final UserRepository userRepository;UserBloc(this.userRepository) : super(UserInitial()) {on<FetchUser>((event, emit) async {emit(UserLoading());final name = await userRepository.fetchUserName();emit(UserLoaded(name));});}
}

3?? 組合使用(main.dart)

void main() {runApp(MultiRepositoryProvider(providers: [RepositoryProvider(create: (_) => UserRepository()),RepositoryProvider(create: (_) => SettingsRepository()),],child: MultiBlocProvider(providers: [BlocProvider(create: (context) => UserBloc(context.read<UserRepository>()),),BlocProvider(create: (context) => SettingsBloc(context.read<SettingsRepository>()),),],child: MyApp(),),),);
}

4?? 頁面中使用

user_page.dart

class UserPage extends StatelessWidget {Widget build(BuildContext context) {return BlocBuilder<UserBloc, UserState>(builder: (context, state) {if (state is UserInitial) {return ElevatedButton(onPressed: () => context.read<UserBloc>().add(FetchUser()),child: Text("Load User"),);} else if (state is UserLoaded) {return Text('Hello, ${state.name}');} else {return CircularProgressIndicator();}},);}
}

settings_page.dart

class SettingsPage extends StatelessWidget {Widget build(BuildContext context) {return BlocBuilder<SettingsBloc, SettingsState>(builder: (context, state) {return SwitchListTile(title: Text('Dark Mode'),value: state.isDarkMode,onChanged: (_) => context.read<SettingsBloc>().add(ToggleTheme()),);},);}
}

? 優點總結

  • 清晰的依賴注入結構:Bloc 和 Repository 解耦,易維護
  • 復用性強:多個 Bloc 可共用同一個 Repository 實例
  • 測試友好:可輕松 mock Repository 進行單元測試
  • 清晰語義:RepositoryProvider 表明它不是 Bloc,而是數據提供者

🚀 Bonus:封裝更進一步

? 已經成功將 MultiRepositoryProviderMultiBlocProvider 封裝到了 AppProviderWrapper 組件中,結構清晰、職責分離得非常好!

下面是總結和優化建議:


? 目前結構回顧

// main.dart
runApp(AppProviderWrapper(child: MyApp()));
// provider_wrapper.dart
class AppProviderWrapper extends StatelessWidget {final Widget child;const AppProviderWrapper({required this.child});...
}

這非常適合中大型項目,可以讓 main.dart 邏輯更純粹,同時也方便后續擴展全局錯誤監聽、日志注入等中間件。


💡 可選優化建議

1. 使用 lazy: false 控制立即初始化 Bloc

有些 Bloc(如 SettingsBloc)可能希望 App 啟動時就立即初始化:

BlocProvider(lazy: false,create: (context) => SettingsBloc(context.read<SettingsRepository>()),
),
2. 使用 const 構造節省 rebuild

如果子 Widget 和 Bloc 無關,記得加 const 以避免重建。

3. 模塊化進一步優化(可選)

可以把 Bloc、Repository 的創建封裝成方法,增強可維護性:

List<RepositoryProvider> buildRepositories() => [RepositoryProvider(create: (_) => UserRepository()),RepositoryProvider(create: (_) => SettingsRepository()),
];List<BlocProvider> buildBlocs(BuildContext context) => [BlocProvider(create: (_) => UserBloc(context.read())),BlocProvider(create: (_) => SettingsBloc(context.read())),
];

這樣 AppProviderWrapper 中就可以這么寫:

child: MultiBlocProvider(providers: buildBlocs(context),child: child,
),

? 總結

現在的結構已經非常標準、清晰,完全符合企業級 Flutter 項目推薦架構。
源碼地址

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

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

相關文章

c++ 語言在無人機應用開發中的應用

C 語言在無人機應用開發中扮演著核心角色&#xff0c;特別是在對性能、實時性、資源利用效率和底層硬件控制有嚴格要求的領域。以下是其主要應用領域&#xff1a; 飛控系統 (Flight Control System - FCS) 核心功能&#xff1a; 這是無人機的大腦。C 用于實現核心的導航、制導與…

Uniapp本地存儲(uni.setStorage)全面解析與實踐指南

在移動應用開發中&#xff0c;本地存儲是不可或缺的核心功能之一。作為跨平臺開發框架&#xff0c;Uniapp提供了一套完善的本地存儲解決方案&#xff0c;使開發者能夠輕松實現數據的持久化存儲。本文將深入探討Uniapp本地存儲的方方面面&#xff0c;從基礎使用到高級技巧&#…

n8n教程:5分鐘部署+自動生AI日報并寫入飛書多維表格

哈嘍&#xff0c;大家好&#x1f44f; 我是阿星&#xff01; 最近n8n太火了。什么是n8n&#xff1f;有點像扣子和dify的綜合體。 簡單來說就是替你打工的「自動化工作流」 我們今天就從部署&#x1f449;搭建第一個工作流。用它實現自動抓取新聞并分類。 教程有點長&#x…

禾納 AET3152AP 電源MOS IC完全替代TDM3307 替代TDM2307泰德電子料 國產芯片

禾納半導體的電源管理芯片AET3152AP不含鹵素和銻&#xff0c;符合Rohs標準&#xff0c;應用在交換機切換&#xff0c;便攜式/臺式機中的電源管理等&#xff0c;可pin to pin替代TDM3307或TDM2307. AET3152AP 封裝為PDFN3030 &#xff0c;最小包裝數為5000pcs AET3152AP工作溫…

專題:2025信創產業新發展+AI趨勢數字化研究報告|附30+份報告PDF匯總下載

原文鏈接&#xff1a;https://tecdat.cn/?p42711 本報告匯總解讀聚焦信創產業核心發展脈絡&#xff0c;以數據驅動視角剖析技術演進與市場變革。信創產業作為國家數字安全與技術自主可控的核心載體&#xff0c;正經歷從“可用”到“好用”的關鍵躍遷。 本報告洞察基于《億歐智…

電子電氣架構 --- 分區電子電氣架構如何支持軟件定義汽車

我是穿拖鞋的漢子,魔都中堅持長期主義的汽車電子工程師。 老規矩,分享一段喜歡的文字,避免自己成為高知識低文化的工程師: 做到欲望極簡,了解自己的真實欲望,不受外在潮流的影響,不盲從,不跟風。把自己的精力全部用在自己。一是去掉多余,凡事找規律,基礎是誠信;二是…

【簡單】344.反轉字符串

題目描述 編寫一個函數&#xff0c;其作用是將輸入的字符串反轉過來。輸入字符串以字符數組 s 的形式給出。 不要給另外的數組分配額外的空間&#xff0c;你必須原地修改輸入數組、使用 O(1) 的額外空間解決這一問題。 示例 1&#xff1a; 輸入&#xff1a;s ["h&quo…

CVE-2025-24813源碼分析與漏洞復現(Tomcat 路徑等效漏洞與反序列化RCE)

漏洞概述 漏洞名稱&#xff1a;Tomcat 路徑等效漏洞反序列化遠程代碼執行&#xff08;RCE&#xff09; CVE 編號&#xff1a;CVE-2025-24813 CVSS 評分&#xff1a;9.8 影響版本&#xff1a; 9.0.0.M1 ≤ Tomcat ≤ 9.0.9810.1.0-M1 ≤ Tomcat ≤ 10.1.3411.0.0-M1 ≤ Tomcat…

深入解析:如何實時獲取Socket接收緩沖區的數據量

在網絡編程中&#xff0c;精確掌握接收緩沖區的數據狀態是優化性能的關鍵。本文將揭秘如何跨平臺獲取socket接收緩沖區的可讀數據量&#xff0c;并分析實際應用中的注意事項。 一、核心API&#xff1a;操作系統級數據探針 1. Windows平臺方案 #include <winsock2.h>// …

Edge卸載應用

Edge安裝應用后&#xff0c;出現在開始菜單&#xff0c;不能卸載。

Cursor Rules 的核心定位與作用

Cursor Rules 是 AI 編程工具 Cursor IDE 中的核心功能&#xff0c;用于約束 AI 生成代碼的行為&#xff0c;確保其符合項目規范、編碼風格或特定技術需求。它本質上是一套持久化、可復用的指令集&#xff0c;會動態插入到 AI 模型的上下文提示中&#xff0c;指導其生成代碼的邏…

多線程爬蟲優化:快速爬取并寫入CSV

在數據驅動的時代&#xff0c;爬蟲技術已成為獲取網絡數據的重要手段。然而&#xff0c;隨著數據量的不斷增加&#xff0c;單線程爬蟲的效率逐漸難以滿足需求。多線程爬蟲通過并行處理&#xff0c;能夠顯著提升爬取速度&#xff0c;同時將數據快速寫入CSV文件&#xff0c;為后續…

Deepseek+墨刀,1min快速生成流程圖!

想要了解快速了解產品邏輯&#xff0c;可以用ds墨刀快速生成流程圖~ deepseek鏈接&#xff1a;https://www.deepseek.com/ 墨刀在線&#xff1a;https://modao.cc/brand 如何操作呢&#xff1f; 1.打開deepseek&#xff0c;輸入以下咒語&#xff0c;讓AI用Mermaid語法繪制流…

LangChain4j流式調用、消息注解與會話記憶

我們先用AiService工具類把調用ai大語言模型的代碼寫出來。因為AiService工具類中整合有記憶、Rag知識庫、tools工具等&#xff0c;我們直接配置調用即可。 我用的是qwen-plus模型。 引入依賴&#xff1a; <dependency><groupId>dev.langchain4j</groupId>…

NtfsWriteLog函數分析之OpenAttributeTableDump

第一部分&#xff1a; NtfsWriteLog( IrpContext, Vcb->MftScb, //注意&#xff1a;Vcb->MftScb NULL, OpenAttributeTableDump, …

DCM4CHEE ARCHIVE LIGHT 源代碼解析(2)-STOWRS

系列文章目錄 DCM4CHEE ARCHIVE LIGHT 源代碼解析(1)-前言DCM4CHEE ARCHIVE LIGHT 源代碼解析(2)-STOWRS文章目錄 系列文章目錄概述一、背景資料1、RESTful服務2、傳輸存儲規范3、服務連接策略4、響應消息狀態二、業務分析1、對象關系2、項目結構3、業務流程三、代碼解析1、w…

Java中間件簡介:構建現代軟件的“隱形橋梁”

Java中間件簡介&#xff1a;構建現代軟件的“隱形橋梁” 在軟件開發的世界里&#xff0c;中間件&#xff08;Middleware&#xff09;是一個既熟悉又神秘的存在。它不像數據庫那樣直接存儲數據&#xff0c;也不像前端那樣與用戶交互&#xff0c;但它卻是現代軟件架構中不可或缺…

Scale AI 的王曉磊帶著對整個 AI 行業動態的深入了解加入 Meta

每周跟蹤AI熱點新聞動向和震撼發展 想要探索生成式人工智能的前沿進展嗎&#xff1f;訂閱我們的簡報&#xff0c;深入解析最新的技術突破、實際應用案例和未來的趨勢。與全球數同行一同&#xff0c;從行業內部的深度分析和實用指南中受益。不要錯過這個機會&#xff0c;成為AI領…

冒煙測試概念速解

最近很多人對冒煙測試這個概念發出疑問。那么我就來簡單解釋一下什么是冒煙測試&#xff0c;以及冒煙測試的由來。 1.冒煙測試的由來 硬件測試的起源&#xff1a;從 “冒煙” 到基礎功能驗證 在電子工程領域&#xff0c;早期工程師在調試新硬件&#xff08;如電路板、芯片&am…

嵌入式學習筆記——day36-多路IO復用

一、基本概念 &#xff08;服務器多客戶端模型&#xff09; 定義&#xff1a; 單線程或單進程同時監測若干個文件描述符是否可以執行IO操作的能力 作用&#xff1a; 應用程序通常需要處理來自多條事件流中的事件&#xff0c;比如我現在用的電腦&#xff0c;需要同時處理鍵盤鼠…