Flutter 中 Dio + Freezed + Retrofit + Json 的组合体验如何?❤

发布于 1周前 作者 songsunli 来自 Flutter

Flutter 中 Dio + Freezed + Retrofit + Json 的组合体验

在 Flutter 开发中,API 请求和数据处理是一个常见的需求。结合 DioFreezedRetrofitJson Serializable 可以带来非常高效的开发体验。以下是一个完整的示例,展示了如何使用这些库来处理分页 API 响应。

前提条件

  • Dio:用于 HTTP 请求
  • Retrofit:生成所有的请求
  • Freezed:生成用于处理的数据模型
  • Json Serializable:生成 JSON 解析逻辑
  • GetIt:依赖注入
  • Build Runner 和其他生成器

pubspec.yaml 中添加依赖项

dependencies:
  flutter:
    sdk: flutter
  dio: ^4.0.0
  retrofit: ^2.0.0
  freezed_annotation: ^0.14.0
  json_annotation: ^4.0.1
  get_it: ^7.2.0

dev_dependencies:
  build_runner: ^2.0.4
  freezed: ^0.14.0
  json_serializable: ^4.0.1

后端返回分页响应

假设后端返回一个分页响应,包含所有分页数据和请求的数据模型,结构如下:

{
  "docs": [
    {
      "id": 1,
      "title": "Post Title",
      "content": "Post Content"
    }
  ],
  "total": 10,
  "page": 1,
  "limit": 10
}

创建基础类

docs 数组可以是任何类型,因此创建一个 PaginatedResponse 类作为基础类。

// paginated_response.dart
import 'package:json_annotation/json_annotation.dart';

part 'paginated_response.g.dart';

@freezed
abstract class PaginatedResponse<T> with _$PaginatedResponse<T> {
  factory PaginatedResponse({
    required List<T> docs,
    required int total,
    required int page,
    required int limit,
  }) = _PaginatedResponse;

  factory PaginatedResponse.fromJson(Map<String, dynamic> json) =>
      _$PaginatedResponseFromJson(json);
}

生成代码:

flutter pub run build_runner build

创建实际的数据模型

例如,创建一个 Post 数据模型。

// post.dart
import 'package:json_annotation/json_annotation.dart';

part 'post.g.dart';

@freezed
abstract class Post with _$Post {
  factory Post({
    required int id,
    required String title,
    required String content,
  }) = _Post;

  factory Post.fromJson(Map<String, dynamic> json) => _$PostFromJson(json);
}

生成代码:

flutter pub run build_runner build

创建 API

使用 Dio + Retrofit 创建 API。

// retrofit_api.dart
import 'package:dio/dio.dart';
import 'package:retrofit/retrofit.dart';
import 'package:your_app/models/paginated_response.dart';
import 'package:your_app/models/post.dart';

part 'retrofit_api.g.dart';

@RetrofitInterface(baseUrl: "https://your-api-endpoint.com")
interface ApiService {
  @GET("/posts")
  Future<PaginatedResponse<Post>> getPosts(
    @Query("page") int page,
    @Query("limit") int limit,
  );
}

生成代码:

flutter pub run build_runner build

配置依赖注入

GetIt 中注册 ApiService

// dependency_injection.dart
import 'package:dio/dio.dart';
import 'package:get_it/get_it.dart';
import 'package:retrofit/retrofit.dart';
import 'retrofit_api.dart';

final getIt = GetIt.instance;

void setupDependencies() {
  final dio = Dio();
  final retrofit = Retrofit.builder()
      .baseUrl("https://your-api-endpoint.com")
      .converterFactory(StandardConverters.create())
      .client(dio)
      .build();

  getIt.registerSingleton<Retrofit>(retrofit);
  getIt.registerFactory<ApiService>(() => retrofit.create(ApiService()));
}

在应用的入口文件(如 main.dart)中调用 setupDependencies

// main.dart
import 'package:flutter/material.dart';
import 'dependency_injection.dart';

void main() {
  setupDependencies();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter App'),
        ),
        body: Center(
          child: Text('Hello, Flutter!'),
        ),
      ),
    );
  }
}

使用 API

在你的 Flutter 组件中使用 ApiService 获取数据。

// posts_page.dart
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'dependency_injection.dart';
import 'retrofit_api.dart';

class PostsPage extends StatefulWidget {
  @override
  _PostsPageState createState() => _PostsPageState();
}

class _PostsPageState extends State<PostsPage> {
  late ApiService apiService;
  late Future<PaginatedResponse<Post>> postsFuture;

  @override
  void initState() {
    super.initState();
    setupDependencies();
    apiService = getIt.get<ApiService>();
    postsFuture = apiService.getPosts(page: 1, limit: 10);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Posts'),
      ),
      body: FutureBuilder<PaginatedResponse<Post>>(
        future: postsFuture,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Center(child: CircularProgressIndicator());
          } else if (snapshot.hasError) {
            return Center(child: Text('Error: ${snapshot.error}'));
          } else {
            final posts = snapshot.data?.docs ?? [];
            return ListView.builder(
              itemCount: posts.length,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text(posts[index].title),
                  subtitle: Text(posts[index].content),
                );
              },
            );
          }
        },
      ),
    );
  }
}

总结

通过这种方式,你可以:

  • 拥有灵活的数据请求模型
  • 只需要一个命令来生成数据、请求等
  • 拥有所有这些库带来的好处,如代码生成、类型安全、易于维护和扩展等

希望这个示例能帮助你在 Flutter 项目中更好地使用 DioFreezedRetrofitJson Serializable


更多关于Flutter 中 Dio + Freezed + Retrofit + Json 的组合体验如何?❤的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter 中 Dio + Freezed + Retrofit + Json 的组合体验如何?❤的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter开发中,结合Dio、Freezed、Retrofit和Json进行网络请求和数据处理的体验非常流畅且高效。这种组合不仅简化了API调用的复杂性,还提高了代码的可读性和可维护性。以下是一个简要的代码示例,展示如何使用这些库进行网络请求和数据解析。

1. 添加依赖

首先,在pubspec.yaml文件中添加所需的依赖:

dependencies:
  flutter:
    sdk: flutter
  dio: ^4.0.0 # 确保使用最新版本
  retrofit: ^2.0.0 # 确保使用最新版本
  freezed_annotation: ^0.14.0 # 确保使用最新版本
  json_annotation: ^4.0.1 # 确保使用最新版本
  build_runner: ^2.0.4 # 用于生成代码

2. 定义数据模型

使用Freezed和Json库定义不可变的数据模型,并自动生成fromJsontoJson方法。

// models/user.dart
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:json_annotation/json_annotation.dart';

part 'user.freezed.dart';
part 'user.g.dart';

@freezed
abstract class User with _$User {
  factory User({
    required String id,
    required String name,
    required String email,
  }) = _User;

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}

// 生成代码
// flutter pub run build_runner build --delete-conflicting-outputs

3. 定义API接口

使用Retrofit定义API接口,结合Dio进行网络请求。

// api/user_api.dart
import 'package:dio/dio.dart';
import 'package:retrofit/retrofit.dart';
import 'package:your_app/models/user.dart';

part 'user_api.g.dart';

@RetrofitInterface(baseUrl: "https://api.example.com/")
interface UserApi {
  @GET("/users/{id}")
  Future<User> getUserById(@Path("id") String id);
}

// 生成代码
// flutter pub run build_runner build --delete-conflicting-outputs

4. 配置Retrofit和Dio

在主应用或某个初始化位置配置Retrofit和Dio实例。

// main.dart
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:retrofit/retrofit.dart';
import 'api/user_api.dart';
import 'models/user.dart';

void main() async {
  final dio = Dio();
  final retrofit = Retrofit.builder()
    .baseUrl("https://api.example.com/")
    .build();

  final userApi = retrofit.create<UserApi>(dio);

  runApp(MyApp(userApi));
}

class MyApp extends StatelessWidget {
  final UserApi userApi;

  MyApp(this.userApi);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Flutter Demo')),
        body: Center(
          child: FutureBuilder<User>(
            future: userApi.getUserById("1"),
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.done) {
                if (snapshot.hasError) {
                  return Text('Error: ${snapshot.error}');
                } else {
                  final user = snapshot.data!;
                  return Text('User: ${user.name} (${user.email})');
                }
              } else {
                return CircularProgressIndicator();
              }
            },
          ),
        ),
      ),
    );
  }
}

总结

通过以上步骤,我们使用Flutter中的Dio、Freezed、Retrofit和Json库实现了一个简单的网络请求和数据解析流程。这种组合不仅简化了代码,还提高了开发效率和代码质量。Freezed提供了不可变的数据模型,Retrofit简化了API调用,而Dio则是一个强大的HTTP客户端库,Json库则帮助我们轻松地进行数据序列化和反序列化。这种组合在现代Flutter开发中非常流行,值得一试。

回到顶部