什么是 SuperController
SuperController
是 GetX 提供的一个 抽象控制器类,它扩展了普通的 GetxController
,可以直接处理:
- 数据状态(加载、成功、空、错误)
- 请求结果缓存
- 网络请求刷新(refresh / retry)
它的核心是和 RxStatus
搭配使用,类似 StateMixin
。
案例
import 'package:flutter/material.dart';
import 'package:get/get.dart';
// ------------------ 1. 创建 GetConnect API --------------------
class PostApi extends GetConnect {
@override
void onInit() {
httpClient.baseUrl = "https://jsonplaceholder.typicode.com";
super.onInit();
}
Future<Response> getPosts() => get("/posts");
}
// -------------------2. 使用 SuperController -------------------
/// SuperController<List<dynamic>>:
/// ① 管理状态(loading/success/empty/error)
/// ② 内置 refresh、生命周期方法
class PostController extends SuperController<List<dynamic>> {
final api = Get.find<PostApi>();
/// 拉取数据
Future<void> fetchPosts() async {
change(null, status: RxStatus.loading()); // 设置加载状态
try {
final response = await api.getPosts();
if (response.statusCode == 200) {
final data = response.body;
if (data.isEmpty) {
change([], status: RxStatus.empty());
} else {
change(data, status: RxStatus.success());
}
} else {
change(null, status: RxStatus.error("请求失败: ${response.statusCode}"));
}
} catch (e) {
change(null, status: RxStatus.error(e.toString()));
}
}
@override
void onDetached() {}
@override
void onInactive() {}
@override
void onPaused() {}
@override
void onResumed() {}
@override
void onHidden() {
// TODO: implement onHidden
}
}
// -----------------------3. 创建 Binding -----------------------
class PostBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<PostApi>(() => PostApi());
Get.lazyPut<PostController>(() => PostController());
}
}
// -----------------------4. 创建页面 ---------------------------
class PostPage extends StatelessWidget {
PostPage({super.key});
final PostController controller = Get.find<PostController>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("GetConnect + SuperController 示例")),
body: Column(
children: [
ElevatedButton(
onPressed: () {
controller.fetchPosts(); // 手动触发请求
},
child: Text("加载数据"),
),
Expanded(
child: controller.obx(
(state) => ListView.builder(
itemCount: state!.length,
itemBuilder: (context, index) {
final post = state[index];
return ListTile(
title: Text(post["title"]),
subtitle: Text(post["body"]),
);
},
),
onLoading: Center(child: CircularProgressIndicator()),
onEmpty: Center(child: Text("暂无数据")),
onError: (err) => Center(child: Text("错误: $err")),
),
),
],
),
);
}
}
// -----------------------5. 路由配置 ---------------------------
void main() {
runApp(
GetMaterialApp(
initialRoute: '/posts',
getPages: [
GetPage(name: '/posts', page: () => PostPage(), binding: PostBinding()),
],
),
);
}

StateMixin
和SuperController
其实 StateMixin
和 SuperController
的核心用途几乎一样:
特性 | StateMixin |
SuperController |
---|---|---|
基础类 | GetxController + StateMixin<T> |
继承 SuperController<T> |
状态管理 | ✅ 有 RxStatus |
✅ 有 RxStatus |
生命周期 | 只有 onInit/onClose |
支持 App/Widget 可见性全生命周期 |
是否强制实现生命周期方法 | ❌ 不强制 | ✅ 必须实现 (哪怕留空) |
适合场景 | 普通页面,数据请求 | 更复杂的场景,需要感知 前后台切换 或 组件隐藏显示 |
- 只需要加载数据、展示数据 → 用
StateMixin
就够了(代码更简洁)。 - 需要额外处理「前后台、暂停恢复」的逻辑 → 用
SuperController
更合适。
SuperController的生命周期
方法 | 触发时机 | 典型用途 |
---|---|---|
onInit() |
控制器 创建时 调用(只执行一次) | 初始化数据、发起首次网络请求、订阅监听 |
onDetached() |
组件与 widget 树 完全分离 时调用 | 清理资源,释放内存 |
onInactive() |
组件处于 非活动状态,但仍在 widget 树中 | 暂停动画、暂停计时器 |
onPaused() |
组件被覆盖,不可见 但仍存在 | 停止耗时操作(视频、网络轮询) |
onResumed() |
组件重新可见、恢复交互 | 重新拉取数据、恢复动画 |
onHidden() |
组件 部分隐藏 时触发 | 可以选择性地减少刷新频率 |
onClose() |
控制器 销毁时 调用(生命周期最后一步) | 释放控制器内的资源、取消订阅、关闭流 |
除了onInit
和onClose
之外,其余5个都是必须实现的方法。这是因为 SuperController
继承自 SuperLifecycle
,而 SuperLifecycle
是一个 抽象类 (abstract class),里面定义了这些 生命周期方法,并且它们是 abstract 方法,没有默认实现。之所以强制实现这些方法是为了让Controller能够接收 Widget 的可见性/生命周期变化。SuperController
不只是管理数据,还可以感知页面或组件的可见性状态,这样方便做 资源管理 / 数据刷新 / 自动暂停任务 等。
在很多时候我们只需要 onInit
/ onClose
就够了。但 SuperController
适合那些需要对 App 前后台切换、页面可见性 做精细管理的场景,比如:
- 做 视频播放列表 → 用户切换出去时自动
pause()
,回来时resume()
- 做 聊天应用 → 页面不可见时停止轮询,回来时再拉新消息
- 做 股票行情 → 切后台就不更新 UI,切回来恢复请求
生命周期图
flowchart TD A["onInit()
控制器创建时调用"] --> B["onReady()
UI首次渲染完成"] B --> C["onResumed()
恢复活跃/前台"] C --> D["onPaused()
进入后台/失去活跃"] D --> E["onInactive()
非活动状态,等待用户操作"] E --> F["onHidden()
页面被部分遮挡"] F --> G["onDetached()
完全分离,不再可见"] G --> H["onClose()
控制器销毁,清理资源"] %% 状态切换说明 C -.-> D D -.-> C D -.-> E E -.-> F F -.-> C %% 样式分组 style A fill:#d9f1ff,stroke:#0366d6,stroke-width:2px style B fill:#d9f1ff,stroke:#0366d6,stroke-width:2px style C fill:#e2ffe2,stroke:#228B22,stroke-width:2px style D fill:#fffacc,stroke:#d6a600,stroke-width:2px style E fill:#fffacc,stroke:#d6a600,stroke-width:2px style F fill:#fffacc,stroke:#d6a600,stroke-width:2px style G fill:#ffe0e0,stroke:#d63333,stroke-width:2px style H fill:#ffe0e0,stroke:#d63333,stroke-width:2px