跳到主要内容

138 篇博文 含有标签「iCoding」

个人简介

查看所有标签

Table 把握关键

· 阅读需 5 分钟
Quany
软件工程师
  • 产品设计方向;
  • 事项;
  • 软件架构;

以下是使用 Flutter Inspector 调试布局问题的完整指南,结合了三个典型问题的解决方案和工具的核心使用逻辑:


一、Flutter Inspector 核心功能

  1. Widget 树可视化
    通过树状结构查看 UI 组件的层级关系,支持选中 Widget 查看其类型、属性和约束条件。这在诊断布局溢出(Overflow)问题时尤为关键,例如当 Text 超出 Row 宽度时,Inspector 会直接标注出尺寸冲突。

  2. 布局浏览器(Layout Explorer)
    可视化弹性布局(Row/Column)的子组件布局参数,支持实时调整 flexalignment 等属性并预览效果。例如在调试无界高度错误时,可通过该工具观察约束传递过程。

  3. 实时属性修改
    直接修改 Widget 的布局属性(如 mainAxisSizecrossAxisAlignment),无需重新编译即可验证修复方案。这对调试不可见的分割线(VerticalDivider)非常有效。

  4. 约束与尺寸诊断
    Details Tree 中查看每个 Widget 的 sizeconstraints,例如当 ListView 被赋予无限高度约束时,会明确显示 height: INFINITY


二、调试三大布局问题实战

问题1:溢出错误(Overflow)

现象Row 末尾出现黄色警告条,控制台报错 Right Overflowed by X pixels

调试步骤

  1. 定位问题组件
    在控制台错误信息中找到引发溢出的 Widget(如 Text)。
  2. 使用 Layout Explorer
    选中 Row,发现 Text 的宽度(447)超过父容器宽度(335)。通过调整 flex:1 验证 Text 能否自动收缩。
  3. 代码修复
    Expanded 包裹 Text,强制其宽度适配父容器:
    Row(children: [
    Expanded(child: Text('Long text...')) // 添加 Expanded
    ])

问题2:无界高度错误(Unbounded height)

现象ListView 未显示内容,控制台报错 Vertical viewport was given unbounded height

调试步骤

  1. 分析约束传递
    Details Tree 中发现 ListView 的高度约束为 INFINITY,因为父 Column 未限制高度。
  2. 约束修正
    Expanded 包裹 ListView,赋予其有限高度约束:
    Column(children: [
    Expanded(child: ListView(...)) // 限制高度
    ])

问题3:不可见的分割线(Invisible VerticalDivider)

现象VerticalDivider 未渲染,无控制台报错。

调试步骤

  1. 检查尺寸约束
    在 Layout Explorer 中发现 VerticalDivider 的高度为 0,因为父 Row 未传递高度约束。
  2. 显式设置高度
    通过 SizedBox 强制指定容器高度:
    SizedBox(
    height: 50, // 显式高度约束
    child: Row(children: [
    VerticalDivider(thickness: 2)
    ])
    )

三、调试方法论(COIN 法则)

  1. Check 错误信息
    通过控制台定位问题组件(如 VerticalDivider 所在的行号)。
  2. Open Layout Explorer
    可视化布局结构,验证子组件的约束传递是否合理。
  3. Inspect 约束细节
    Details Tree 中查看 sizeconstraints 的精确数值。
  4. Navigate 代码修复
    根据诊断结果修改布局逻辑,优先使用 Expanded/SizedBox 约束系统。

四、关键布局原则

  1. 约束传递方向
    父 Widget 向下传递约束,子 Widget 向上返回尺寸。例如 Column 会先收集子组件高度,再计算自身布局。
  2. Expanded 的核心作用
    在弹性布局中强制子组件填充剩余空间,避免溢出或无界错误。但需注意 Expanded 会覆盖子组件的固有尺寸。
  3. 显式尺寸的必要性
    对无默认尺寸的组件(如 VerticalDivider),必须通过父容器或 LayoutBuilder 提供明确约束。

总结

通过 Flutter Inspector 的 Layout ExplorerDetails Tree,开发者可以直观诊断 90% 的布局问题。掌握约束传递机制和弹性布局特性后,配合 ExpandedSizedBox 等约束工具,能快速修复溢出、无界尺寸和不可见组件等问题。建议在调试时始终遵循 COIN 法则,逐步缩小问题范围。

微信公众号

微信公众号

Table 优化方向

· 阅读需 1 分钟
Quany
软件工程师
  • 代码编程方面: 减少判断空的情况;
  • 路由设计

微信公众号

微信公众号

订单列表试图

· 阅读需 1 分钟
Quany
软件工程师

接口层面:

  1. 桌台列表;未对接;
  2. 审核列表;未建立正确的数据模型;
  3. 订单详情; 由于接口变得数据模型;

微信公众号

微信公众号

Json to Dart

· 阅读需 1 分钟
Quany
软件工程师
{
"tableCount": 10,
"personCount": 50,
"oneToTwo": 5,
"twoToFour": 10,
"fourToSix": 15,
"sixToEight": 10,
"GeThanEight": 10,
"bookingOrderListCOs": [
{
"bookingOrderId": 1,
"corporationId": 101,
"shopId": 201,
"shopName": "Shop A",
"guestId": 301,
"bookingTime": "2024-04-01T12:00:00Z",
"bookingTimeLocal": "2024-04-01T20:00:00+08:00",
"guestCount": 2,
"bookingTags": [
{
"tagId": 1,
"tagName": "Special Request"
}
],
"contactFirstName": "John",
"contactLastName": "Doe",
"status": "CONFIRMED",
"childount": 0,
"childSeatCount": 0,
"orderType": 1,
"avgDiningTime": 120,
"tableIds": [1001, 1002],
"createTime": "2024-03-31T12:00:00Z",
"diningTime": 120,
"guestBookingRemark": "Please provide a high chair."
},
{
"bookingOrderId": 2,
"corporationId": 102,
"shopId": 202,
"shopName": "Shop B",
"guestId": 302,
"bookingTime": "2024-04-02T14:00:00Z",
"bookingTimeLocal": "2024-04-02T22:00:00+08:00",
"guestCount": 4,
"bookingTags": [
{
"tagId": 2,
"tagName": "VIP"
}
],
"contactFirstName": "Jane",
"contactLastName": "Smith",
"status": "CREATED",
"childount": 1,
"childSeatCount": 1,
"orderType": 2,
"avgDiningTime": 180,
"tableIds": [1003],
"createTime": "2024-03-31T14:00:00Z",
"diningTime": 180,
"guestBookingRemark": "Require a vegetarian menu."
}
]
}

https://app.quicktype.io/

微信公众号

微信公众号

Flutter for RS Tables

· 阅读需 5 分钟
Quany
软件工程师

任务

  • 预订
    • 列表视图
    • [ ]时间线视图
  • 排队
    • 列表视图
    • 时间线视图
  • 审核

以下是 Flutter 异常收集与在线分析的完整方案,结合官方推荐方法和第三方服务实现高效监控:


一、异常捕获核心方法

  1. 全局捕获 Dart 异常
    使用 runZonedGuarded 包裹 runApp,拦截所有未处理的同步/异步异常:

    runZonedGuarded(
    () async {
    WidgetsFlutterBinding.ensureInitialized();
    runApp(MyApp());
    },
    (error, stackTrace) {
    // 上报至分析平台
    Crashlytics.recordError(error, stackTrace);
    }
    );
  2. 捕获 Framework 异常
    重写 FlutterError.onError 处理布局渲染等框架级错误:

    FlutterError.onError = (details) {
    if (kReleaseMode) {
    // 生产环境上报
    Zone.current.handleUncaughtError(details.exception, details.stack!);
    } else {
    // 开发环境打印日志
    FlutterError.dumpErrorToConsole(details);
    }
    };
  3. 自定义错误界面
    替换默认红屏页面为友好提示,同时记录异常:

    ErrorWidget.builder = (details) => CustomErrorScreen(
    exception: details.exception,
    stack: details.stack,
    );

二、在线分析工具推荐

  1. Sentry

    • 优势:开源可自建,支持源码映射还原混淆堆栈
    • 集成:通过 sentry_flutter 包自动捕获异常并关联设备信息
    • 看板:提供错误趋势图、影响用户数统计
  2. Firebase Crashlytics

    • 优势:与 Google 生态深度集成,实时告警
    • 功能:自动聚类相似崩溃,支持日志附加用户操作路径
  3. 腾讯 Bugly

    • 本地化服务:中文界面优化,支持 NDK 层崩溃分析
    • 特色:兼容混合开发(Flutter + Native 堆栈关联)
  4. ELK Stack(自建)

    • 场景:企业级私有化部署
    • 流程:通过 Logstash 收集日志 → Elasticsearch 存储 → Kibana 可视化分析

三、最佳实践建议

  1. 环境区分处理

    • 开发环境:在控制台打印完整堆栈,启用热重载快速调试
    • 生产环境:屏蔽敏感信息,仅上报必要元数据(如设备型号、OS 版本)
  2. 错误边界设计

    • 使用 ErrorWidget 包裹高风险组件(如第三方插件)
    • 对网络请求添加 try-catch 并附加重试机制
  3. 上下文增强

    • 记录用户操作路径(如页面跳转、按钮点击)辅助复现问题
    • 附加应用状态信息(如 Redux Store、本地缓存数据)
  4. 性能优化

    • 使用 Isolate 处理耗时日志压缩/加密操作,避免阻塞主线程
    • 配置 logrotate 防止本地日志文件过大

四、常见异常类型与处理

异常类型典型案例解决方案
NoSuchMethod空对象调用方法添加空安全操作符 ?. 或判空逻辑
StateErrorList 越界/未找到元素使用 list.elementAtOrNull 替代直接访问
PlatformException原生插件通信失败检查通道注册一致性,添加兼容性降级处理
RenderingError布局约束冲突使用 Flutter Inspector 检查 Widget 树

通过结合上述工具链,可实现异常从捕获、存储到分析的闭环。推荐中小团队直接采用 Sentry 或 Firebase 降低运维成本,大型企业可基于 ELK 构建定制化监控体系。若需代码示例或特定工具集成细节,可进一步说明需求。


微信公众号

微信公众号

RestoSuite之预定App预定

· 阅读需 22 分钟
Quany
软件工程师

代办事项

  • [] 预约博物馆

以下是设计 GetX Service 的核心原则与步骤,结合了服务设计思维和微服务架构的最佳实践,并基于 Flutter GetX 框架的特性进行优化:


一、GetX Service 的核心设计原则

  1. 单一职责原则 (SRP)
    每个 GetxService 应专注于一个独立的功能模块(如用户认证、数据缓存、网络请求等),避免功能混杂。例如,网页4中提到的 Service 类专注于通过 SharedPreferences 实现数据持久化。
    实现方式:将不同业务逻辑拆分为独立的 Service 类(如 AuthService、`CacheService``)。

  2. 持久化与全局访问
    GetxService 的生命周期与应用一致,不会被自动销毁,适合存储全局状态或长期数据。需通过依赖注入(如 Get.put())初始化,并通过 Get.find() 全局访问。
    实现方式:在应用启动时初始化 Service(见网页4中的 initServices 函数)。

  3. 松耦合与高内聚
    Service 应通过接口与其他模块通信(如通过方法调用或事件驱动),避免直接依赖具体实现。例如,网页4中的 Service 类封装了 SharedPreferences 的读写操作,对外仅暴露 getCounter 方法。

  4. 异步初始化与生命周期管理
    支持异步初始化(如 Get.putAsync()),并可通过 onInit()onReady()onClose() 管理资源加载和释放。例如,网页4中通过 await Get.putAsync() 初始化服务。


二、GetX Service 设计步骤

1. 定义 Service 类

继承 GetxService,并实现业务逻辑:

class AuthService extends GetxService {
Future<void> initialize() async {
// 初始化代码(如加载本地用户信息)
}

Future<void> login(String email, String password) async {
// 登录逻辑
}


void onClose() {
// 释放资源(如关闭数据库连接)
super.onClose();
}
}

2. 依赖注入与初始化

在应用启动时通过 Get.put()Get.putAsync() 注入 Service:

Future<void> main() async {
await Get.putAsync(() async => AuthService().initialize());
runApp(MyApp());
}

3. 全局访问与调用

在任意位置通过 Get.find() 获取 Service 实例并调用方法:

// 在 Widget 中调用
ElevatedButton(
onPressed: () => Get.find<AuthService>().login("user@example.com", "password"),
child: Text("登录"),
);

4. 数据持久化与状态管理

结合本地存储(如 SharedPreferencesHive)实现数据持久化:

class CacheService extends GetxService {
final SharedPreferences _prefs;

CacheService(this._prefs);

String get token => _prefs.getString('token') ?? '';

Future<void> saveToken(String token) async {
await _prefs.setString('token', token);
}
}

三、高级设计技巧

  1. 服务分层

    • 基础服务层:处理技术细节(如网络请求、数据库操作)。
    • 业务服务层:组合基础服务实现业务逻辑(如 OrderService 调用 ApiServiceCacheService)。
  2. 事件驱动通信
    通过 GetX 的事件总线(GetX Event)实现服务间解耦通信:

    // 发送事件
    Get.emit(UserLoggedInEvent(user));

    // 监听事件
    Get.on<UserLoggedInEvent>((event) => updateUI());
  3. 单元测试与 Mock
    通过依赖注入替换 Service 实现(如使用 MockAuthService 替代真实服务)。


四、参考案例(来自网页4)

网页4中的 Service 类通过 SharedPreferences 实现计数器的持久化,展示了以下设计模式:

  • 依赖注入:通过 Get.putAsync() 初始化服务。
  • 封装数据操作:对外暴露 getCounter 方法,隐藏具体实现细节。
  • 生命周期管理:虽然没有显式使用 onInit,但通过异步初始化确保数据加载完成。

通过以上原则和步骤,可以设计出高内聚、低耦合且易于维护的 GetX Service,适用于全局状态管理、复杂业务逻辑封装等场景。

以下是关于 GetX Event 的详细介绍,结合其核心功能、使用场景和最佳实践,帮助开发者在 Flutter 应用中实现跨组件/模块的松耦合通信:


一、GetX Event 的核心概念

GetX Event 是 GetX 框架提供的一种轻量级事件总线(Event Bus)机制,用于在不同组件(如 Widget、Service、Controller)之间传递消息,无需直接依赖或引用。它的核心优势在于解耦和异步通信。

关键特性:

  • 跨层级通信:可在任何位置发送/监听事件,如页面跳转、全局状态更新等。
  • 类型安全:通过泛型指定事件数据类型(如 UserLoginEvent)。
  • 自动内存管理:通过 Get.onClose 自动注销监听,避免内存泄漏(需手动配置)。
  • 与 GetX 生态无缝集成:天然适配 GetX 的依赖注入和生命周期管理。

二、GetX Event 核心 API

1. 发送事件

通过 Get.emit(event) 发送事件对象:

// 定义自定义事件类
class UserLoginEvent {
final String username;
UserLoginEvent(this.username);
}

// 发送事件
Get.emit(UserLoginEvent("Alice"));

2. 监听事件

通过 Get.on<T>(callback) 监听特定类型事件:

// 监听事件并处理
final subscription = Get.on<UserLoginEvent>((event) {
print("用户登录:${event.username}");
});

3. 取消监听

手动取消事件订阅(避免内存泄漏):

subscription.cancel();  // 取消单个监听
Get.offAll<UserLoginEvent>(); // 取消所有该类型监听

三、使用场景与最佳实践

场景 1:跨页面状态同步

需求:在设置页修改主题颜色,通知首页更新 UI。
实现

// 定义主题切换事件
class ThemeChangeEvent {
final Color newColor;
ThemeChangeEvent(this.newColor);
}

// 在设置页发送事件
Get.emit(ThemeChangeEvent(Colors.blue));

// 在首页监听事件
class HomePage extends StatelessWidget {

Widget build(BuildContext context) {
Get.on<ThemeChangeEvent>((event) => updateTheme(event.newColor));
return ...;
}
}

场景 2:Service 与 Controller 解耦

需求:用户登录成功后,通知多个模块更新数据。
实现

// AuthService 发送登录事件
class AuthService extends GetxService {
Future<void> login() async {
// ...登录逻辑
Get.emit(UserLoginSuccessEvent(user));
}
}

// ProfileController 监听事件
class ProfileController extends GetxController {

void onInit() {
Get.on<UserLoginSuccessEvent>((_) => loadProfile());
super.onInit();
}
}

场景 3:异步任务完成通知

需求:文件下载完成后通知 UI 刷新。
实现

// 在下载服务中发送事件
class DownloadService {
void startDownload() {
// ...下载逻辑
Get.emit(DownloadCompleteEvent(filePath));
}
}

// 在 Widget 中监听
Get.on<DownloadCompleteEvent>((event) => showDownloadCompleteToast(event.filePath));

四、高级技巧与注意事项

1. 事件分类与组织

  • 按功能模块分类:创建 events/ 目录,按业务划分事件类(如 auth_events.dartui_events.dart)。
  • 使用继承统一管理
    abstract class BaseEvent {}
    class NetworkEvent extends BaseEvent {}
    class UserEvent extends BaseEvent {}

2. 生命周期管理

  • 自动注销监听:结合 GetxControlleronClose 自动取消订阅:
    class MyController extends GetxController {
    late Worker _eventListener;


    void onInit() {
    _eventListener = Get.on<UserEvent>(_handleEvent);
    super.onInit();
    }


    void onClose() {
    _eventListener.cancel();
    super.onClose();
    }
    }

3. 性能优化

  • 避免高频事件:对于高频事件(如滚动事件),建议使用 debouncethrottle
    Get.on<ScrollEvent>((event) => handleScroll(), 
    condition: () => _canProcessScroll // 条件控制
    );

4. 测试策略

  • Mock 事件流:在单元测试中模拟事件触发:
    test('Test login event', () async {
    final mockEvent = UserLoginEvent("test");
    Get.emit(mockEvent);
    expect(controller.isLoggedIn, true);
    });

五、与其他状态管理方案对比

方案适用场景优点缺点
GetX Event跨组件/模块的松散通信无需依赖引用,天然解耦不适合局部状态管理
GetBuilder父子组件状态同步精确控制刷新范围需要手动管理依赖关系
GetX Obx响应式数据驱动的 UI 更新自动跟踪依赖,代码简洁过度使用可能导致性能问题

六、完整示例代码

// events/user_events.dart
class UserLoginEvent {
final String username;
UserLoginEvent(this.username);
}

// services/auth_service.dart
class AuthService extends GetxService {
Future<void> login(String username) async {
// 模拟登录
await Future.delayed(Duration(seconds: 2));
Get.emit(UserLoginEvent(username));
}
}

// controllers/profile_controller.dart
class ProfileController extends GetxController {
String? username;


void onInit() {
// 监听登录事件
Get.on<UserLoginEvent>((event) {
username = event.username;
update(); // 触发 UI 更新
});
super.onInit();
}
}

// UI 使用
Get.put(ProfileController());
Get.find<AuthService>().login("Alice");

通过合理使用 GetX Event,可以实现高度解耦、易于维护的 Flutter 应用架构,尤其适合中大型项目的模块化开发。建议根据实际业务需求,将其与 GetX 的其他功能(如 Service、Controller)结合使用。

以下是基于 GetX 框架设计嵌套路由的完整指南,结合官方文档和开发者实践经验,涵盖核心实现步骤和高级应用场景:


一、嵌套路由核心实现步骤

1. 创建嵌套导航容器

在父页面中使用 Navigator 组件作为嵌套路由容器,并通过 Get.nestedKey 定义唯一标识符:

// 父页面视图 (如 main/view.dart)
Navigator(
key: Get.nestedKey(1), // 唯一标识符,用于区分不同导航栈
initialRoute: '/step1', // 初始子路由
onGenerateRoute: controller.onGenerateRoute, // 路由解析逻辑
)

2. 定义路由解析逻辑

在父页面控制器中实现 onGenerateRoute 方法,管理子页面的路由跳转和过渡动画:

// 父页面控制器 (如 main/controller.dart)
Route? onGenerateRoute(RouteSettings settings) {
switch (settings.name) {
case '/step1':
return GetPageRoute(
settings: settings,
page: () => const Step1Page(),
transition: Transition.topLevel, // 自定义过渡动画
);
case '/step2':
return GetPageRoute(
settings: settings,
page: () => const Step2Page(),
transition: Transition.rightToLeftWithFade,
);
default:
return null;
}
}

3. 执行子路由跳转

通过 Get.toNamedid 参数指定目标导航栈:

// 跳转到子页面
Get.toNamed('/step2', id: 1); // id=1 对应 nestedKey(1) 的导航栈

二、嵌套路由参数传递与接收

1. 动态参数传递

在子路由路径中使用动态参数(如商品ID):

// 定义动态子路由
GetPage(
name: '/products/:id',
page: () => ProductDetailPage(),
)
// 跳转时传递参数
Get.toNamed('/products/123', id: 1);

2. 参数接收

在子页面通过 Get.parameters 获取参数:

final productId = Get.parameters['id'];  // 获取 '123'

三、嵌套导航栏与多级路由联动

1. 底部导航栏 + 嵌套路由

实现类似管理后台的布局(侧边栏固定,内容区域动态切换):

// 父页面视图结构
Column(
children: [
Expanded(child: Navigator(...)), // 内容区域
_buildBottomNavBar(), // 底部导航栏
]
)
// 导航栏按钮控制子路由
ElevatedButton(
onPressed: () => Get.toNamed('/step1', id: 1),
child: Text('Step 1'),
)

2. 浏览器历史兼容

在 GetX 5.0+ 中,嵌套路由支持深度链接和浏览器前进/后退按钮:

// 配置命名路由
GetMaterialApp(
getPages: [
GetPage(name: '/', page: () => HomePage()),
GetPage(
name: '/products',
page: () => ProductListPage(),
children: [ // 定义子路由树
GetPage(name: '/:id', page: () => ProductDetailPage()),
],
),
],
)

四、高级场景:动态子路由加载

1. 按需加载模块

结合 Get.lazyPut 实现子模块的懒加载:

GetPage(
name: '/admin',
page: () => AdminDashboard(),
binding: BindingsBuilder(() {
Get.lazyPut(() => AdminService()); // 仅当访问/admin时初始化
}),
)

2. 路由守卫

通过 GetMiddleware 实现权限验证:

class AuthMiddleware extends GetMiddleware {

RouteSettings? redirect(String? route) {
return Get.find<AuthService>().isLoggedIn ? null : RouteSettings(name: '/login');
}
}
// 应用中间件
GetPage(
name: '/profile',
page: () => ProfilePage(),
middlewares: [AuthMiddleware()],
)

五、注意事项

  1. 导航栈隔离
    每个 nestedKey 对应独立导航栈,避免跨栈操作导致状态混乱。

  2. 生命周期管理
    使用 GetxControlleronInit/onClose 管理子页面资源。

  3. 兼容性策略
    GetX 5.0+ 优化了嵌套路由的浏览器兼容性,建议升级到最新版本。


典型应用场景

场景实现方案优势
购物向导流程分步骤嵌套路由保持顶部进度条固定,内容动态切换
管理后台侧边菜单 + 内容区嵌套路由局部刷新提升性能
语言学习应用底部导航栏 + 选项卡嵌套路由支持多维度导航

完整代码示例可参考:网页1 GitHub仓库


以下是 Flutter 读取环境变量文件的几种常用方法及其实现细节,结合不同场景需求提供灵活解决方案:


一、官方推荐:--dart-define-from-file(Flutter 3.7+)

适用场景:多环境配置(如开发、测试、生产环境),需与原生平台(Android/iOS)共享变量。
实现步骤

  1. 创建 JSON 配置文件
    在项目根目录新建 config.json 文件,定义键值对:

    {
    "API_KEY": "your_api_key",
    "ENV_MODE": "production",
    "BASE_URL": "https://api.example.com"
    }
  2. 编译时注入变量
    通过命令行参数指定配置文件:

    flutter run --dart-define-from-file=config.json
    # 或构建发布包
    flutter build apk --dart-define-from-file=config.json
  3. Dart 代码读取变量
    使用 String.fromEnvironmentint.fromEnvironment

    final apiKey = String.fromEnvironment('API_KEY');
    final envMode = String.fromEnvironment('ENV_MODE', defaultValue: 'development');

原生平台同步

  • Android:在 app/build.gradle 中通过 dartEnvVar 直接引用变量(如生成 BuildConfig 字段)。
  • iOS:编译时自动生成 flutter_export_environment.shGenerated.xcconfig,通过 Info.plist 引用。

二、第三方库 dotenv(适用于本地开发)

适用场景:需要动态加载 .env 文件,避免硬编码敏感信息。
实现步骤

  1. 添加依赖
    pubspec.yaml 中引入:

    dependencies:
    flutter_dotenv: ^5.1.0
  2. 创建 .env 文件
    在项目根目录定义变量:

    DEBUG_MODE=true
    FIREBASE_API_KEY=abc123
  3. 加载与使用

    import 'package:flutter_dotenv/flutter_dotenv.dart';

    void main() async {
    await dotenv.load(fileName: ".env");
    final apiKey = dotenv.env['FIREBASE_API_KEY'];
    runApp(MyApp(apiKey: apiKey));
    }

注意事项

  • .env 加入 .gitignore 避免泄露敏感信息。
  • 支持多环境文件(如 .env.prod, .env.staging),通过 --dart-define=ENV_FILE=.env.prod 动态切换。

三、Web 端特殊处理

问题:Flutter Web 无法直接访问系统环境变量,需通过前端注入。
解决方案

  1. web/index.html 中注入变量

    <script>
    window.config = {
    API_ENDPOINT: "{{API_ENDPOINT}}",
    ANALYTICS_ID: "{{ANALYTICS_ID}}"
    };
    </script>
  2. Dart 代码通过 dart:js 读取

    import 'dart:js' as js;

    String get apiEndpoint => js.context['config']['API_ENDPOINT'];

四、安全与最佳实践

  1. 敏感信息加密

    • 对密钥类变量使用 flutter_config--dart-define 结合 CI/CD 管道注入。
    • 避免在版本控制中提交 .envconfig.json
  2. 多环境管理
    使用不同配置文件:

    # 开发环境
    flutter run --dart-define-from-file=config.dev.json
    # 生产环境
    flutter build apk --dart-define-from-file=config.prod.json
  3. IDE 集成
    在 VS Code 或 Android Studio 中配置启动参数,自动加载对应环境:

    // .vscode/launch.json
    "args": ["--dart-define-from-file=config.staging.json"]

五、跨平台兼容性问题

  1. iOS URL 处理
    iOS 的 xcconfig 文件会将 // 识别为注释,需对包含 URL 的变量进行转义:

    {"IMAGE_CDN": "https:\\/\\/cdn.example.com"}
  2. Android 变量类型限制
    Gradle 仅支持字符串类型变量,数字需在代码中转换:

    final timeout = int.parse(String.fromEnvironment('REQUEST_TIMEOUT'));

通过以上方法,可根据项目需求选择最适合的环境变量管理策略。对于需要与原生深度集成的场景,优先使用 --dart-define-from-file;快速开发场景推荐 dotenv 的灵活性。


在 GetX 框架中,ControllerService 是两种核心设计模式,它们在架构中承担不同的角色,但通过依赖注入机制实现了高效协作。以下是两者的关键区别与联系:


一、核心职责对比

维度ControllerService
定位业务逻辑与 UI 状态管理单元(如页面级逻辑)全局服务层(如数据持久化、网络请求封装)
生命周期与绑定的 Widget 同步销毁常驻内存,应用退出时销毁
典型用途管理页面数据流、事件响应、状态更新跨页面共享数据、封装底层能力(如 API 调用)
代码示例通过 GetxController 子类实现通过普通类或 GetxService 实现

二、协作关系解析

1. 依赖注入机制

  • Controller 调用 Service
    Controller 通过 Get.find() 获取 Service 实例,实现跨模块功能复用:
    class UserController extends GetxController {
    final AuthService _authService = Get.find(); // 注入全局服务
    void login() => _authService.authenticate();
    }
  • Service 独立性
    Service 不直接依赖 Controller,保持高内聚低耦合特性

2. 生命周期联动

  • 初始化顺序
    通过 Bindings 在路由层优先初始化 Service,再加载 Controller:
    class AppBindings extends Bindings {
    void dependencies() {
    Get.lazyPut(() => ApiService()); // 先注册服务
    Get.put(UserController()); // 再注册控制器
    }
    }
  • 资源释放
    Controller 在 onClose() 中手动释放 Service 连接(如关闭数据库)

三、设计模式最佳实践

1. Controller 设计原则

  • 单一职责:每个 Controller 仅处理单一页面/组件的逻辑
  • 状态隔离:通过 .obs 变量实现 UI 的自动响应式更新
    class CartController extends GetxController {
    final items = <Product>[].obs; // 响应式数据
    void addItem(Product product) => items.add(product);
    }

2. Service 设计原则

  • 无状态设计:避免持有 UI 相关数据,专注业务能力封装
  • 线程安全:通过 GetxService 实现单例模式,确保全局访问安全

四、典型应用场景

场景Controller 作用Service 作用
用户登录处理表单验证、按钮状态执行 API 请求、Token 存储
电商购物车管理商品列表、总价计算同步到后端、本地缓存
多语言切换触发 UI 重绘加载语言包、持久化用户选择

五、常见误区

  1. 滥用 Service 持有 UI 状态
    ❌ 错误:将页面级变量放入 Service
    ✅ 修正:通过 Controller 管理,Service 仅处理数据读写

  2. 忽略生命周期管理
    ❌ 错误:在 Service 中直接引用 Controller
    ✅ 修正:通过事件总线(如 GetXWorker)解耦通信


通过合理划分 Controller 与 Service 的边界,开发者可以构建出 高可维护性强扩展性 的 Flutter 应用架构。实际开发中建议结合 GetX 官方文档 和具体业务需求灵活调整。


{
"ENV_MODE": "dev",
"MQTT_URL": "mqtt-01.test.restosuite.ai",
"MQTT_USER": "mqtt_username",
"BASE_URL": "https://api.test.com",
"MOCK_URL": "https://mock.mengxuegu.com/mock/67b934bc441fe7482c224f9e/mock",
"BO_URL": "https://bo.test.restosuite.ai"
}

微信公众号

RestoSuite之订位

· 阅读需 14 分钟
Quany
软件工程师

Figma 拥有丰富的 AI 插件生态,涵盖设计生成、图像处理、文案填充、代码转换等多个方向。以下是目前(截至 2025 年 3 月)主流的 AI 插件分类及代表性工具:


一、AI 设计生成类

  1. Builder.io
    • 输入文字描述(如「类似 Everlane 的产品页」)即可生成完整 UI 设计稿,支持电商、App 注册页等多种场景,生成结果可直接在 Figma 中编辑。
  2. Dora AI
    • 通过提示词生成响应式网页设计稿(支持 PC 和移动端),生成结果包含可编辑的图层和自动布局,新用户可免费体验 3 次。
  3. 即时 AI
    • 输入详细文字描述(如页面结构、内容类型)生成高保真 UI 设计图,支持浏览器直接使用,无需本地安装。

二、AI 图像处理类

  1. ComfyUI 系列插件
    • 支持接入本地或云端 GPU 运行 ComfyUI 工作流,实现文生图、图生图、智能抠图、背景融合等功能,可自定义参数如步数、降噪强度等。
  2. Magician
    • 通过文本生成图标、插画和文案,支持 14 种语言,提供「魔法咒语」功能自动优化设计元素。基础功能免费,高级功能需订阅。

三、AI 内容填充类

  1. NoMoreWrite
    • 一键填充多行业模拟数据(如金融账户、电商商品、物联网设备),支持批量操作和自定义文本循环填充,提升原型设计效率。
  2. 智能填充(Quick Fill 2)
    • 自动匹配真实场景数据,如用户评论、社交账号信息,每天免费 10 次使用额度。

四、AI 代码转换类

  1. Locofy Lightning
    • 将 Figma 设计稿转换为响应式代码(支持 React、Vue 等框架),40 秒内完成转换并允许开发人员调试代码细节。
  2. Codia AI Design
    • 上传界面截图即可生成可编辑的 Figma 设计稿,自动添加布局约束,适合快速复刻现有网页。

使用建议:


以上插件均可在 Figma 社区中直接安装,部分需注册 API 密钥或订阅高级服务。如需完整列表,可访问 Figma 插件市场 搜索「AI」关键词。

根据最新行业评测和苹果产品线分析,搭载 M3 Ultra 芯片的 Mac Studio 目前是苹果 GPU 性能最强的设备。以下是其核心优势和技术细节:


一、GPU 架构与性能

  1. 80 核 GPU 设计
    M3 Ultra 的 GPU 采用苹果自研架构,拥有 80 个计算核心,支持以下关键技术:

    • 动态缓存(Dynamic Caching):智能分配显存资源,提升 GPU 利用率
    • 硬件加速网格着色(Mesh Shading):优化 3D 建模和游戏渲染效率,实测在 GFXBench 4K Aztec Ruins 测试中达到 374 FPS,领先 NVIDIA RTX 5070 Ti 约 20%
    • 光线追踪(Ray Tracing):实现电影级光影效果,接近 NVIDIA RTX 5080 的 90% 性能
  2. 统一内存架构优势
    最高支持 512GB LPDDR5x 统一内存,其中 448GB 可分配为 VRAM(需手动调整 macOS 设置),远超消费级显卡的显存容量。这使得 Mac Studio 可直接本地运行 6000 亿参数的 DeepSeek-R1 大语言模型,而传统多 GPU 方案需要 10 倍以上功耗。


二、实际应用场景表现

  1. AI 开发领域

    • 运行 Llama 8B、Gemma 29B 等模型时,性能超越 Intel i9 + RTX 5090 的高端 PC
    • 在 Geekbench AI 基准测试中,全精度模式得分比 M3 Max 提升 63.6%
  2. 3D 创作与渲染

    • Cinebench 2024 GPU 测试得分约 20,000,领先 AMD Radeon RX 7900 XTX 25%
    • 影视后期特效制作效率提升 2.6 倍,DNA 测序速度提升 3.3 倍

三、扩展与能效

  1. Thunderbolt 5 支持
    提供 120Gbps 传输带宽,可同时连接多台 8K 显示器或高速存储设备,突破传统工作站扩展瓶颈。

  2. 超低功耗设计
    即使满载运行 DeepSeek-R1 模型,整机功耗仅 200W,比同性能多 GPU 方案节能 90%,符合苹果 2030 碳中和目标。


四、产品定位与竞品对比

指标Mac Studio (M3 Ultra)NVIDIA RTX 5090
显存容量最高 448GB (可分配)24GB GDDR7
内存带宽819GB/s1TB/s (HBM3e 显存)
典型功耗200W450W (单卡)
AI 开发兼容性macOS 原生优化依赖 CUDA 生态

推荐组合:使用 Mac Studio 进行本地 AI 原型开发,搭配云端 NVIDIA H100 服务器处理超大规模训练任务。


总结

M3 Ultra 的 GPU 在 显存容量、能效比、统一内存架构 上具有革命性突破,尤其适合需要本地运行大模型或处理超大规模数据的开发者。尽管在纯算力上稍逊于顶级消费级显卡(如 RTX 5080),但其 系统级优化与生态整合能力 重新定义了高性能计算设备的可能性。

以下是2025年最新乘机携带物品限制清单,综合民航局规定和实际案例整理:


一、绝对禁止携带(随身/托运均不可)

  1. 危险物品

    • 枪支弹药、爆炸物、管制刀具(包括仿真枪、钢珠枪、发令枪等)
    • 易燃易爆品:氢气罐、汽油、烟花爆竹、镁棒、强磁性物品
    • 剧毒/腐蚀性物品:氰化物、硫酸、汞(水银)、放射性物质
  2. 特殊物品

    • 酒精含量≥70%的酒精饮料
    • 自喷压力容器类:发胶、摩丝、防晒喷雾、保湿喷雾(无论容量大小)
    • 充电宝/锂电池:额定能量>160Wh(约43000mAh)或标识模糊的

二、可托运但禁止随身携带

  1. 液体类

    • 酒精含量24%-70%的酒精饮料(每人托运≤5L)
    • 酒精湿巾/消毒液:酒精含量≤70%,单瓶≤500mL
    • 液态火锅油、辣椒油等食用液体
  2. 工具类

    • 长度>6cm的普通刀具(如菜刀、水果刀)
    • 登山杖、棒球棍等钝器(需包装完好)

三、可随身携带但禁止托运

  1. 电子设备

    • 笔记本电脑、相机等含锂电池设备(电池不可拆卸时)
    • 充电宝:标识清晰且额定能量≤100Wh(约27000mAh)
  2. 特殊用途物品

    • 婴儿液态乳制品、糖尿病患者液态药品(需现场安检确认)
    • 医用氧气瓶(需医院证明并提前向航司申报)

四、限制性携带物品

  1. 化妆品

    • 单瓶容器标注≤100mL(实际用量不影响判定),总量≤1000mL
    • 例外:指甲油、染发剂等含易燃成分的化妆品完全禁止
  2. 食品

    • 香肠腊肉:商业包装可携带,自制需真空密封且无异味
    • 固体火锅底料可随身带,液态底料需托运
  3. 其他

    • 打火机/火柴:每人限带1个普通打火机(不可托运)
    • 宠物:猫狗等需检疫证明,使用航空箱托运(禁止入客舱)

五、特殊注意事项

  1. 锂电池管理

    • 备用电池每人限带2块,需单独绝缘包装
    • 飞行中禁止使用充电宝,且需全程关闭电源
  2. 行李尺寸限制

    • 国内航班手提行李≤20×40×55cm,托运行李≤40×60×100cm
    • 超规格乐器(如大提琴)需提前申请占座托运

违规处理建议

若携带违禁品被查获,可选择:

  1. 现场放弃物品
  2. 寄存机场(按日收费)
  3. 改签航班后补托运(限可托运物品)

温馨提示:出发前可通过航司官网或机场服务热线(如重庆机场023-966666)查询最新规定。跨境航班需额外遵守目的地国家检疫要求(如澳洲禁止肉类入境)。

以下是2025年最新科学解酒方法整合,结合传统经验和医学研究,分三类推荐:


一、科学解酒方法(优先推荐)

  1. 补水和电解质

    • 温蜂蜜水:蜂蜜中的果糖可加速酒精代谢,缓解头痛;
    • 椰子水/运动饮料:补充因酒精利尿流失的钾、钠,每小时饮用500ml温水或含电解质饮品;
    • 西瓜汁或番茄汁:高水分促排尿,番茄中的特殊果糖可加速酒精分解。
  2. 保护胃黏膜

    • 牛奶/酸奶:蛋白质包裹胃壁,延缓酒精吸收,酸奶中的钙还能缓解烦躁;
    • 鸡蛋或燕麦:酒后2小时食用,半胱氨酸中和乙醛毒性,维生素B1减少乳酸堆积。
  3. 物理降温与休息

    • 冷敷后颈或手腕10分钟,缓解心跳加速和面部潮红;
    • 右侧卧睡:减少胃酸反流和胰管压迫风险,切忌仰卧以防呕吐物窒息。

二、民间验证有效方法

  1. 蔬果类

    • 芹菜汁:缓解酒后头痛脑胀,直接榨汁饮用;
    • 葡萄/香蕉:葡萄中的酒石酸降低乙醇浓度,香蕉补钾缓解乏力。
  2. 食疗配方

    • 绿豆甘草汤:绿豆50g+甘草10g煮汤,促酒精代谢;
    • 葛根水:饮酒前饮用可护肝,酒后饮用助醒酒。

三、解酒误区(避免踩坑)

  1. 浓茶/咖啡加重脱水:咖啡因加剧心跳和头痛,优先选择温水;
  2. 强行催吐危险:可能引发贲门撕裂或急性胰腺炎,仅适合神志清醒者轻抠喉咙;
  3. 解酒药无效:市面产品无法加速代谢,维生素B仅缓解部分不适。

紧急就医信号

若出现以下情况,立即拨打120:

  • 昏迷不醒、呼吸频率<8次/分钟;
  • 呕吐物带血或咖啡色液体;
  • 抽搐或体温低于35℃。

预防醉酒建议

  1. 饮酒前:喝酸奶或吃鸡蛋(延缓酒精吸收50%);
  2. 饮酒时:避免混酒,每杯间隔15分钟,优先选择低度酒;
  3. 基因检测:亚洲40%人群缺乏乙醛脱氢酶(喝酒脸红者),建议滴酒不沾。

注意:以上方法仅缓解不适,酒精无安全剂量,长期饮酒仍会损伤肝脏和神经系统。

微信公众号

RestoSuite之预定 App

· 阅读需 1 分钟
Quany
软件工程师

协助任务

  • 通知中心
  • pin 弹窗组件
  • 预定设置-高级库存管理:lib/pages/setting/widget/plan_stock.dart

微信公众号

315打假

· 阅读需 5 分钟
Quany
软件工程师

一、食品安全:从“舌尖隐患”到贴身风险

  1. 翻新卫生巾/纸尿裤产业链
    梁山希希纸制品有限公司收购残次品卫生巾、婴儿纸尿裤,经简单翻新后贴上“麦酷酷”“自由点”等品牌标签二次销售,威胁女性健康。涉事企业已被查封,负责人被控制,济宁市启动专项整治行动。

  2. 保水虾仁“注冰增重”
    盐城海创源等企业通过过量添加保水剂(磷酸盐超标30倍)和包冰工艺增重,1斤冻虾仁解冻后仅剩3两虾肉,且隐瞒添加剂信息。市场监管总局已介入调查。

  3. 一次性内裤徒手制作不灭菌
    河南商丘多家代工厂(如梦阳服饰)在垃圾堆旁徒手缝制内裤,使用含苯系物的“枪水”去污,产品菌落超标12倍,浪莎、初医生等品牌涉事。商丘市监局已查封涉事车间。


二、数字经济与隐私安全:技术滥用成重灾区

  1. AI骚扰电话产业链
    智优擎科技等企业利用AI外呼机器人(日拨10万次)和虚拟运营商“小号”(无需实名),形成骚扰电话黑色产业链。工信部已关停涉事线路并核查数据。

  2. 隐私窃取“信息黑洞”
    云企智能、绿信科技通过嵌入短视频平台的“获客软件”,1分钟窃取6条用户隐私数据,日处理量达百亿条。国家网信办将开展专项整改。

  3. 手机抽奖连环陷阱
    诺诺网等平台通过自动跳转抽奖页面诱导充值,用户需连续6个月充值4000元才能用完“200元话费券”,80%用户中途放弃。


三、服务乱象:从“维修刺客”到金融陷阱

  1. 啄木鸟维修平台虚报故障
    国内最大维修平台“啄木鸟”培训员工虚构故障(如开个水龙头收费100元),燃气灶换点火器成本20元却收250元,平台抽佣40%。重庆市场监管局已进驻调查。

  2. 电子签高利贷套路
    借贷宝、人人信平台以“砍头息”(如借款5000元实收3500元)和展期费牟利,年化利率近6000%,放贷人使用虚假身份规避法律追责。


四、其他重点曝光问题

非标电线电缆:南宁、贵阳五金市场售卖未达国标的电线,安全隐患严重。 • 黄桃罐头黑幕:个别厂家使用烂桃翻新,篡改生产日期。


五、监管部门行动

市场监管总局:全面彻查“保水虾仁”、非标电线等违法行为,拟于5月上线“全国食品安全举报系统”。 • 工信部:关停骚扰电话线路,清理违法外呼软件。 • 地方政府:山东济宁、河南商丘等地连夜查封涉事企业并启动专项整治。

如需查看完整曝光名单和案例细节,可参考央视财经、新京报等权威报道。

微信公众号

微信公众号

这周发生了什么

· 阅读需 8 分钟
Quany
软件工程师

以下是这周编程技术领域的一些重要动态:

工具与平台更新

  • JDK 24 进入发布阶段:JDK 24 已进入首个候选发布阶段,计划于2025年3月18日正式发布。它包含24项新特性,涵盖核心Java库、语言规范、安全库、HotSpot和Java工具等方面。
  • 字节跳动Trae国内版上线:字节跳动的AI编程产品Trae国内版正式上线,配置了先进的AI模型,支持代码补全、理解、Bug修复及自然语言生成代码等功能,为开发者提供高效、智能化的编程体验。

行业趋势

  • AI主导代码生产趋势加速:Anthropic CEO预测,未来3到6个月内AI将编写90%的代码,一年内几乎包揽全部编程工作。这一趋势促使开发者提升AI相关技能,同时也引发对软件工程师职业前景的思考。
  • 低代码/无代码平台兴起:低代码和无代码平台使开发更加便捷,无需深厚编程知识即可构建强大应用,有助于简化开发流程、缩短产品上市时间并促进快速创新。

未来展望

  • AI编程工具持续进化:AI编程助手将更加智能,能够更好地理解开发者意图,自动生成高质量代码,并在代码优化、调试等方面提供更强大支持。
  • 量子计算与编程融合加深:随着量子计算技术的发展,未来可能出现专门针对量子计算的编程语言和工具,推动量子计算在更多领域的应用。

这些动态反映了编程技术领域的快速发展和变革,开发者需要不断学习和适应新技术,以保持竞争力。

----------------------------Flutter

以下是Flutter中常见的状态管理方案:

  1. Provider:由Flutter官方推荐,基于依赖注入,简单易用,适合中小型应用。
  2. Getx:全能框架,用于状态管理、路由和依赖注入,非常适用于低到中等复杂度的应用程序。
  3. Riverpod:由Provider的作者开发,功能更强大、灵活且类型安全,状态管理与BuildContext解耦,适用于大型应用的开发。

以下是目前Flutter中最流行的状态管理方案:

1. Riverpod

  • 特点:由Provider的作者开发,功能更强大、灵活且类型安全,状态管理与BuildContext解耦,适用于大型应用的开发。
  • 使用示例
    final counterProvider = StateNotifierProvider<CounterModel, int>((ref) {
    return CounterModel();
    });

    class CounterModel extends StateNotifier<int> {
    CounterModel() : super(0);

    void increment() {
    state++;
    }
    }

    void main() {
    runApp(ProviderScope(child: MyApp()));
    }

    class MyApp extends StatelessWidget {

    Widget build(BuildContext context) {
    return MaterialApp(
    home: Scaffold(
    appBar: AppBar(title: Text('Riverpod Example')),
    body: Center(
    child: Consumer(
    builder: (context, ref, child) {
    final count = ref.watch(counterProvider);
    return Text('Count: $count');
    },
    ),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => context.read(counterProvider.notifier).increment(),
    child: Icon(Icons.add),
    ),
    ),
    );
    }
    }
  • 优点:解耦上下文,类型安全,易于测试,支持异步状态。

2. Provider

  • 特点:Flutter官方推荐的状态管理方案之一,基于依赖注入,简单易用,适合中小型应用。
  • 使用示例
    class Counter with ChangeNotifier {
    int _count = 0;
    int get count => _count;

    void increment() {
    _count++;
    notifyListeners();
    }
    }

    void main() {
    runApp(
    ChangeNotifierProvider(
    create: (context) => Counter(),
    child: MyApp(),
    ),
    );
    }

    class MyApp extends StatelessWidget {

    Widget build(BuildContext context) {
    return MaterialApp(
    home: Scaffold(
    appBar: AppBar(title: Text('Provider Example')),
    body: Center(
    child: Consumer<Counter>(
    builder: (context, counter, child) {
    return Text('Count: ${counter.count}');
    },
    ),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => Provider.of<Counter>(context, listen: false).increment(),
    child: Icon(Icons.add),
    ),
    ),
    );
    }
    }

3. Getx

  • 特点:全能框架,用于状态管理、路由和依赖注入,非常适用于低到中等复杂度的应用程序。
  • 使用示例
    void main() => runApp(MaterialApp(home: Home()));

    class Home extends StatelessWidget {
    var count = 0.obs;


    Widget build(context) => Scaffold(
    appBar: AppBar(title: Text("counter")),
    body: Center(
    child: Obx(() => Text("$count")),
    ),
    floatingActionButton: FloatingActionButton(
    child: Icon(Icons.add),
    onPressed: () => count++,
    ));
    }
  • 优点:简单易用,性能优秀,内置依赖注入和路由管理功能。

4. Redux

  • 特点:具有集中式存储、操作和减速器的可预测状态管理,适用于需要强大可预测性和工具的应用程序。
  • 使用示例
    enum Actions { Increment }

    int counterReducer(int state, dynamic action) {
    return action == Actions.Increment ? state + 1 : state;
    }

    void main() {
    final store = Store<int>(counterReducer, initialState: 0);
    runApp(FlutterReduxApp(title: 'Flutter Redux Demo', store: store));
    }

    class FlutterReduxApp extends StatelessWidget {
    final Store<int> store;
    final String title;

    FlutterReduxApp({Key key, this.store, this.title}) : super(key: key);


    Widget build(BuildContext context) {
    return StoreProvider<int>(
    store: store,
    child: MaterialApp(
    theme: ThemeData.dark(),
    title: title,
    home: Scaffold(
    appBar: AppBar(title: Text(title)),
    body: Center(
    child: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: [
    StoreConnector<int, String>(
    converter: (store) => store.state.toString(),
    builder: (context, count) {
    return Text(
    'The button has been pushed this many times: $count',
    style: Theme.of(context).textTheme.display1,
    );
    },
    )
    ],
    ),
    ),
    floatingActionButton: StoreConnector<int, VoidCallback>(
    converter: (store) {
    return () => store.dispatch(Actions.Increment);
    },
    builder: (context, callback) {
    return FloatingActionButton(
    onPressed: callback,
    tooltip: 'Increment',
    child: Icon(Icons.add),
    );
    },
    ),
    ),
    ),
    );
    }
    }

5. BLoC

  • 特点:通过将业务逻辑与UI分离,便于代码复用和测试,适合中大型应用。
  • 使用示例
    class CounterBloc {
    final _counterController = StreamController<int>();
    Stream<int> get counter => _counterController.stream;

    int _count = 0;
    void increment() {
    _count++;
    _counterController.sink.add(_count);
    }

    void dispose() {
    _counterController.close();
    }
    }

    void main() {
    final counterBloc = CounterBloc();
    runApp(Provider.value(value: counterBloc, child: MyApp()));
    }

    class MyApp extends StatelessWidget {

    Widget build(BuildContext context) {
    return MaterialApp(
    home: Scaffold(
    appBar: AppBar(title: Text('BLoC Example')),
    body: Center(
    child: StreamBuilder<int>(
    stream: Provider.of<CounterBloc>(context).counter,
    builder: (context, snapshot) {
    return Text('Count: ${snapshot.data ?? 0}');
    },
    ),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => Provider.of<CounterBloc>(context).increment(),
    child: Icon(Icons.add),
    ),
    ),
    );
    }
    }

6. MobX

  • 特点:采用响应式编程,简化状态管理,适合需要灵活状态管理的项目。
  • 使用示例
    class CounterStore {

    int count = 0;


    void increment() {
    count++;
    }
    }

    void main() {
    final store = CounterStore();
    runApp(Provider.value(value: store, child: MyApp()));
    }

    class MyApp extends StatelessWidget {

    Widget build(BuildContext context) {
    return MaterialApp(
    home: Scaffold(
    appBar: AppBar(title: Text('MobX Example')),
    body: Center(
    child: Observer(
    builder: (_) => Text('Count: ${Provider.of<CounterStore>(context).count}'),
    ),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => Provider.of<CounterStore>(context).increment(),
    child: Icon(Icons.add),
    ),
    ),
    );
    }
    }

这些状态管理方案各有优缺点,选择哪种方案取决于项目的具体需求和复杂度。

flutter 待加库

  • flutter_native_splash:启动屏

微信公众号

微信公众号