什么叫做数据拉取
在应用开发中,数据拉取(Data Fetching)指的是 从外部数据源获取数据到应用内部使用 的过程。
常见的数据源包括:
- 远程接口(API/服务器):比如调用
https://api.github.com/users
获取用户信息。 - 本地数据库:比如
SQLite
、Hive
读取保存的数据。 - 文件系统:比如读取 JSON、CSV 文件。
简单说:“数据拉取”就是 应用主动向外部要数据,拿回来以后展示在 UI 上。
常用工具:GetConnect
、Dio
、StateMixin
、SuperController
。
GetConnect是什么
GetConnect
是 GetX 内置的网络请求工具,可以替代 http
包,部分功能类似 Dio
,但更轻量、和 GetX 结合更紧密。它支持:
- GET、POST、PUT、DELETE 请求
- 自动 JSON 解析
- 设置
baseUrl
、请求头、拦截器 - 与
StateMixin
/SuperController
搭配更新 UI
入门案例
代码
// ------------------ 1. 创建 GetConnect API --------------------
class PostApi extends GetConnect {
/// 初始化
/// class GetConnect extends GetConnectInterface {
/// abstract class GetConnectInterface with GetLifeCycleBase {
/// onInit() → 实例创建时触发
@override
void onInit() {
// 设置基础 URL
httpClient.baseUrl = "https://jsonplaceholder.typicode.com";
super.onInit();
}
/// get("/posts"):①发送Get请求 ②制定请求路径:baseUrl+/posts
/// ③返回一个Future<Response>对象
/// https://jsonplaceholder.typicode.com/posts
Future<Response> getPosts() => get("/posts");
}
// -------------------2. 创建 Controller ---------------------------------
class PostController extends GetxController {
final api = Get.find<PostApi>();
// 数据列表
var posts = <dynamic>[].obs;
// 状态
var isLoading = false.obs;
var isEmpty = false.obs;
var error = "".obs;
void fetchPosts() async {
/// isLoading.value = true 表示开始请求
isLoading.value = true;
isEmpty.value = false;
error.value = "";
try {
// 发送get请求:请求并且等到拿到响应
final response = await api.getPosts();
debugPrint("Status Code: ${response.statusCode}");
// 处理响应
if (response.statusCode == 200) {
/// 获取响应数据
final data = response.body;
if (data.isEmpty) {
// 如果数据为空,清空列表并更新状态
posts.clear();
isEmpty.value = true;
} else {
// 如果数据不为空,更新列表并清空状态
posts.value = data;
}
} else {
/// 处理错误
error.value = "请求失败: ${response.statusCode}";
}
} catch (e) {
/// 处理异常
error.value = e.toString();
} finally {
/// 请求结束
isLoading.value = false;
}
}
}
// -----------------------3. 创建 Binding --------------------------------
/// 延迟注入的核心好处就是 按需创建对象,避免顺序依赖和不必要的资源占用。
/// 通过 Get.lazyPut,我们可以在需要的时候再创建实例,而不是在应用启动时就创建所有实例。
class PostBinding extends Bindings {
@override
void dependencies() {
// ✅ 延迟注入 PostApi
Get.lazyPut<PostApi>(() => PostApi());
// ✅ 延迟注入 PostController
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 示例")),
body: Column(
children: [
ElevatedButton(
onPressed: () {
// 点击按钮触发请求
controller.fetchPosts();
},
child: Text("加载数据"),
),
Expanded(
// 使用 Obx 监听状态变化
child: Obx(() {
// 监听 isLoading 状态
if (controller.isLoading.value) {
//如果正在加载isLoading=true,显示进度指示器
//CircularProgressIndicator: 进度指示器
return Center(child: CircularProgressIndicator());
} else if (controller.error.isNotEmpty) {
// 如果发生错误,显示错误信息
// Text: 显示错误信息
return Center(child: Text("错误: ${controller.error.value}"));
} else if (controller.posts.isEmpty) {
// 如果数据为空,显示暂无数据
// Text: 显示暂无数据
return Center(child: Text("暂无数据"));
} else {
// 如果数据不为空,显示列表
return ListView.builder(
// itemCount: 列表项数量
itemCount: controller.posts.length,
// itemBuilder: 构建列表项
// index: 当前索引, 从0开始
// itemBuilder 会循环构建 itemCount 次
itemBuilder: (context, index) {
// 获取当前列表项数据
final post = controller.posts[index];
return ListTile(
title: Text(post["title"]),
subtitle: Text(post["body"]),
);
},
);
}
}),
),
],
),
);
}
}
// -----------------------4.路由配置(将 Binding 和页面绑定)---------------------
void main() {
runApp(
GetMaterialApp(
initialRoute: '/posts',
getPages: [
GetPage(
name: '/posts',
page: () => PostPage(),
binding: PostBinding(), // ✅ 页面进入时自动注入依赖
),
],
),
);
}

关键代码
声明一个
GetConnect
class PostApi extends GetConnect { /// 初始化 /// class GetConnect extends GetConnectInterface { /// abstract class GetConnectInterface with GetLifeCycleBase { /// onInit() → 实例创建时触发 @override void onInit() { // 设置基础 URL httpClient.baseUrl = "https://jsonplaceholder.typicode.com"; super.onInit(); } /// get("/posts"):①发送Get请求 ②制定请求路径:baseUrl+/posts /// ③返回一个Future<Response>对象 /// https://jsonplaceholder.typicode.com/posts Future<Response> getPosts() => get("/posts"); }
创建
GetConnect
并且注册到容器中/// 延迟注入的核心好处就是 按需创建对象,避免顺序依赖和不必要的资源占用。 /// 通过 Get.lazyPut,我们可以在需要的时候再创建实例,而不是在应用启动时就创建所有实例。 class PostBinding extends Bindings { @override void dependencies() { // ✅ 延迟注入 PostApi Get.lazyPut<PostApi>(() => PostApi()); // ✅ 延迟注入 PostController Get.lazyPut<PostController>(() => PostController()); } }
这里使用
Bindings
创建,而且是使用懒加载的方式。会在final api = Get.find<PostApi>();
的时候创建。调用定义的
getPosts()
方法发送请求:final response = await api.getPosts();
GetConnect 的常用方法和属性
常用 HTTP 方法
方法 | 描述 | 返回类型 |
---|---|---|
get(String url, {Map<String, String>? headers}) |
发起 GET 请求 | Future<Response> |
post(String url, dynamic body, {Map<String, String>? headers}) |
发起 POST 请求 | Future<Response> |
put(String url, dynamic body, {Map<String, String>? headers}) |
发起 PUT 请求 | Future<Response> |
patch(String url, dynamic body, {Map<String, String>? headers}) |
发起 PATCH 请求 | Future<Response> |
delete(String url, {Map<String, String>? headers}) |
发起 DELETE 请求 | Future<Response> |
⚠️
body
可以是Map
、List
、JSON 字符串等,GetConnect 会自动处理Content-Type
。
常用属性
属性 | 描述 |
---|---|
httpClient.baseUrl |
基础 URL,用于简化请求路径。get("/posts") → 实际请求 baseUrl + "/posts" |
httpClient.timeout |
请求超时时间,默认 10 秒,可设置为 Duration(seconds: 15) |
httpClient.headers |
默认请求头,全局设置,如 "Authorization": "Bearer xxx" |
httpClient.defaultContentType |
默认内容类型,GET 默认 application/json ,POST 可以自定义 |
httpClient.maxAuthRetries |
请求失败自动重试次数,默认为 0 |
其他常用方法
方法 | 描述 |
---|---|
request(String url, String method, {body, headers}) |
通用请求方法,可以自定义 HTTP 方法 |
formData(Map<String, dynamic> data) |
将数据转成 FormData 发送,用于文件上传 |
file(String url, File file, {String? field, Map<String, String>? headers}) |
上传文件(多用于 POST) |
getStream(String url, {Map<String, String>? headers}) |
获取流式响应,用于大文件下载或 SSE |
cancelRequests({bool force = false}) |
取消正在进行的请求 |
响应处理相关
get
/post
等方法返回 Response
,常用属性:
属性 | 描述 |
---|---|
statusCode |
HTTP 状态码,例如 200、404、500 |
statusText |
状态描述,例如 “OK” |
body |
返回的内容(通常是 JSON 转 Map/List) |
bodyBytes |
原始二进制数据 |
headers |
响应头 |
拦截器 & 生命周期方法(可选)
onInit()
→ GetConnect 实例创建时调用,用于设置 baseUrl、默认 header。onRequest(Request request)
→ 请求拦截,可修改请求。onResponse(Response response)
→ 响应拦截,可统一处理返回。onError(Response response)
→ 请求出错时触发,可统一处理错误。
拦截器非常适合做 统一 Token 注入、全局错误处理。
使用示例
class MyApi extends GetConnect {
@override
void onInit() {
httpClient.baseUrl = "https://jsonplaceholder.typicode.com";
httpClient.timeout = Duration(seconds: 15);
httpClient.headers['Authorization'] = 'Bearer xxx';
super.onInit();
}
Future<Response> getPosts() => get("/posts");
Future<Response> createPost(Map<String, dynamic> data) => post("/posts", data);
@override
void onRequest(Request request) {
print("Request: ${request.method} ${request.url}");
super.onRequest(request);
}
@override
void onResponse(Response response) {
print("Response: ${response.statusCode}");
super.onResponse(response);
}
@override
void onError(Response response) {
print("Error: ${response.statusCode}");
super.onError(response);
}
}