GetX:数据拉取与GetConnect

什么叫做数据拉取

在应用开发中,数据拉取(Data Fetching)指的是 从外部数据源获取数据到应用内部使用 的过程。

常见的数据源包括:

  • 远程接口(API/服务器):比如调用 https://api.github.com/users 获取用户信息。
  • 本地数据库:比如 SQLiteHive 读取保存的数据。
  • 文件系统:比如读取 JSON、CSV 文件。

简单说:“数据拉取”就是 应用主动向外部要数据,拿回来以后展示在 UI 上。

常用工具:GetConnectDioStateMixinSuperController

GetConnect是什么

GetConnectGetX 内置的网络请求工具,可以替代 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(), // ✅ 页面进入时自动注入依赖
        ),
      ],
    ),
  );
}

关键代码

  1. 声明一个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");
    }
    
  2. 创建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>();的时候创建。

  3. 调用定义的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 可以是 MapList、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);
  }
}

×

喜欢就点赞,疼爱就打赏