最近社区发生了件不大不小的事Getx删库跑路了,后来Getx的仓库又恢复访问了,随即我又发了一篇,有人评论了一句"吃流量",但作为自媒体,不吃点流量吃啥吗?我不仅要吃流量,而且还要吃到撑。
在浅谈Getx删库跑路了中我曾经给过一些迁移建议,但毕竟有的朋友特别喜欢Getx这种大而全的框架,可是GetX的维护活跃在最近一年的时间里并不能算,如果不让他们用GetX那还有什么类似的替代品吗?
当然有!
而且必须是sint!
SINT是啥?
首先介绍一下高保真 Flutter 基础设施的四大支柱:
- 状态管理
- 依赖注入
- 路由导航
- 国际化。
而SINT便是那个专注于这四大支柱的框架:
| 支柱 (Pillar) | 核心职责 (Responsibility) | 关键组件与 API |
|---|---|---|
| S - State | 状态管理:处理响应式数据流、UI 自动刷新及异步状态监听。 | SintController, SintBuilder, Obx, .obs, Rx types, Workers, SintStatus, SintListener |
| I - Injection | 依赖注入:管理对象的生命周期、解耦组件依赖及智能内存回收。 | Sint.put, Sint.find, Sint.lazyPut, Sint.putAsync, Bindings, SmartManagement |
| N - Navigation | 路由导航:实现无 Context 跳转、参数传递、中间件拦截及 Web 兼容性。 | SintPage, Sint.toNamed, Sint.toInitial, route/path/queryParam, middleware, SintMaterialApp, back() |
| T - Translation | 国际化翻译:提供丝滑的多语言切换、动态加载及端点翻译映射。 | .tr extension, Translations class, locale management, loadTranslations, PathTranslator, translateEndpoints |
SINT脱胎于GetX (v5.0.0-rc),也就是说SINT是Getx的Fork。
那我们为什么要弃用Getx而选用SINT呢?
因为这四大支柱之外的一切都被移除了:没有 HTTP 客户端,没有动画,没有字符串校验,没有通用工具类。结果就是是代码量比 GetX 少了 37.7%------12,849 行 vs 20,615 行。
SINT的核心原则则是:
- 性能:没有 Stream 或 ChangeNotifier 的开销。极低的内存占用。
- 生产力 :简洁的语法。只需一个 import:
import 'package:sint/sint.dart'; - 组织性:Clean Architecture 结构。5 个模块,每个对应一个支柱。
换言之,
- Getx大包大揽,啥都干
- SINT只干正确的事
正如SINT这个名字一般------S + I + N + T --- State, Injection, Navigation, Translation。不多不少,恰到好处。
从GetX迁移到SINT
按照文档的迁移指导,那是相当的简单了。
- 在
pubspec.yaml中将get:替换为sint: - 将
import 'package:get/get.dart'替换为import 'package:sint/sint.dart' - 原有的
Get.调用依然有效 ------ 建议逐步替换为Sint.以消除弃用警告 GetMaterialApp→SintMaterialApp``GetPage→SintPage
以Flutter经典的计数器为例,用SINT实现一次:
dart
void main() => runApp(SintMaterialApp(
initialRoute: '/',
sintPages: [
SintPage(name: '/', page: () => Home()),
SintPage(name: '/other', page: () => Other()),
],
));
class Controller extends SintController {
var count = 0.obs;
increment() => count++;
}
class Home extends StatelessWidget {
@override
Widget build(context) {
final c = Sint.put(Controller());
return Scaffold(
appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))),
body: Center(
child: ElevatedButton(
child: Text("Go to Other"),
onPressed: () => Sint.toNamed('/other'),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: c.increment,
),
);
}
}
class Other extends StatelessWidget {
final Controller c = Sint.find();
@override
Widget build(context) {
return Scaffold(body: Center(child: Text("${c.count}")));
}
}
怎么样?是不是还是熟悉的味道?
性能怎么样?
SINT 为速度而生。每一根支柱都经过了 Open Neom 标准的严格审计。
让我们看一组高保真性能表现(基准测试)数据:
| 支柱 (Pillar) | 指标 (Metric) | 结果 (Result) | 上下文/测试条件 (Context) |
|---|---|---|---|
| S (状态) | 响应式 .obs 更新 |
0.09 us/op | 50,000 次连续更新 |
| S (状态) | 简单 update() |
0.11 us/op | 50,000 次连续更新 |
| S (状态) | 带监听器的 Rx | 6.23 us/op | 30,000 次压力测试 |
| I (注入) | 注册表查找 | 1.34 us/find | 深度为 10 的依赖解析 |
| N (导航) | 中间件延迟 | 23 ms | 5 层嵌套中间件链 |
| T (翻译) | 动态插值 | 2.65 us/op | 10,000 次翻译参数查找 |
为什么 SINT 更快:
- 支柱 S :通过使用直接的
ListNotifier传播,避开了Stream的额外开销。速度比 BLoC 快 15-30 倍。 - 支柱 I :在带有生命周期管理的全局注册表中实现 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( 1 ) O(1) </math>O(1) 哈希查找。
- 支柱 N :无 Context 导航移除了路由过程中沉重的组件树(Widget Tree)查找操作。
一些使用示例
为了多写几个字,还是简单介绍一下使用示例吧。
状态管理
2种方式:响应式 (.obs + Obx) and 简单的 (SintBuilder)。
dart
// 响应式
var count = 0.obs;
Obx(() => Text('${count.value}'));
// 简单的
SintBuilder<Controller>(
builder: (_) => Text('${_.counter}'),
)
用于响应式副作用(Side Effects)的监听器(Workers):
dart
ever(rx, callback); // Every change
once(rx, callback); // First change only
debounce(rx, callback); // After pause (400ms default)
interval(rx, callback); // Max once per duration (1s default)
用于异步状态管理的 SintStatus:
dart
status.value.when(
loading: () => spinner,
success: (data) => content(data),
error: (err) => errorView(err),
empty: () => emptyView,
);
依赖注入
无Context的依赖注入:
dart
Sint.put(AuthController());
Sint.lazyPut(() => ApiService());
await Sint.putAsync(() => SharedPreferences.getInstance());
final controller = Sint.find<AuthController>();
路由导航
无需 Context 的路由管理 ------ 针对 Web 深度链接(Deep Links)及移动端同步优化:
dart
SintMaterialApp(
initialRoute: '/',
translateEndpoints: true, // i18n URLs (web)
snackBarStyle: SintSnackBarStyle(...), // Global theming
sintPages: [
SintPage(name: '/', page: () => Home()),
SintPage(name: '/book/:bookId', page: () => BookDetail()),
SintPage(name: '/search', page: () => Search()),
],
)
// Navigation
Sint.toNamed('/book/abc123?ref=home');
Sint.back(); // Web-safe
Sint.toInitial(); // Hard reset to home
Sint.toInitial(keep: {AuthController}); // Keep specific controllers
// RESTful parameter extraction
String? id = Sint.routeParam; // 'abc123'
String? id = Sint.pathParam('bookId'); // 'abc123'
String? ref = Sint.queryParam('ref'); // 'home'
String sort = Sint.queryParamOrDefault('sort', 'a'); // 'a' (default)
// Snackbar with global style
Sint.snackbar('Title', 'Message');
国际化
通过 .tr 实现国际化 ------ 现已同步支持 URL 路由映射:
dart
Text('hello'.tr);
Text('welcome'.trParams({'name': 'Serzen'}));
Sint.updateLocale(Locale('es', 'ES'));
// Lazy loading per module
await Sint.loadTranslations(() async {
final json = await rootBundle.loadString('assets/i18n/shop.json');
return {'es': Map<String, String>.from(jsonDecode(json))};
});
// URL path translation (automatic when translateEndpoints: true)
// Your translation keys double as URL segment mappings:
// 'book' → 'libro' (ES), 'livre' (FR), 'buch' (DE)
//
// PathTranslator handles:
// canonicalizePath('/libro/abc') → '/book/abc' (incoming)
// localizePath('/book/abc', 'es') → '/libro/abc' (outgoing)
// URL 路径翻译(当 `translateEndpoints: true` 时自动执行)
// 你的翻译键值(Translation Keys)同时兼作 URL 段的映射:
// 'book' → 'libro' (西班牙语), 'livre' (法语), 'buch' (德语)
//
// PathTranslator 处理逻辑:
// 规范化路径:canonicalizePath('/libro/abc') → '/book/abc' (处理入口请求)
// 本地化路径:localizePath('/book/abc', 'es') → '/libro/abc' (处理出口路由)
结语
SINT是你的菜吗?
不过,我自己确实没有使用过SINT。所以,以上内容基本来自官方文档。
欢迎关注我的微信公众号:OpenFlutte。