Flutter 三方库 dio 的鸿蒙化适配与网络请求实战指南

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
摘要
本文基于 Flutter for OpenHarmony 跨平台技术,以网络请求三方库 dio 为例,从零完成了鸿蒙设备上的网络请求能力适配。从依赖引入、网络服务封装、数据模型构建到完整页面实现,覆盖了加载状态、错误处理与刷新能力,同时验证了代码在鸿蒙设备上的可运行性,为 Flutter 开发者在鸿蒙生态中实现网络请求功能提供了可直接落地的实践方案。
一、前言
网络请求是移动应用开发中最核心的能力之一,而 dio 作为 Flutter 生态中最主流的网络请求三方库,以其简洁的 API、强大的拦截器与表单支持,被广泛应用于各类 Flutter 项目中。在开源鸿蒙跨平台开发场景中,我们同样可以基于 dio 快速实现稳定、可靠的网络请求能力。
本文将完整记录如何在 Flutter for OpenHarmony 项目中接入 dio,封装通用网络请求服务,并实现一个完整的网络数据列表页面,所有代码均已在鸿蒙设备上验证通过。
二、项目依赖配置
首先,我们需要在项目的 pubspec.yaml 中添加 dio 依赖,本文使用稳定版 ^5.4.3:

dependencies:
  flutter:
    sdk: flutter
  dio: ^5.4.3 # 网络请求三方库

三、通用网络服务封装
为了统一管理网络请求,我们封装了单例模式的 NetworkService 类,统一处理请求、响应与错误,同时支持 GET/POST/PUT/DELETE 等常用请求方法:

import 'package:dio/dio.dart';

class NetworkService {
  // 单例模式
  static final NetworkService instance = NetworkService._internal();
  late Dio dio;

  NetworkService._internal() {
    dio = Dio(BaseOptions(
      baseUrl: 'https://jsonplaceholder.typicode.com', // 示例API地址
      connectTimeout: const Duration(seconds: 10),
      receiveTimeout: const Duration(seconds: 10),
    ));

    // 可选:添加请求拦截器
    dio.interceptors.add(LogInterceptor(responseBody: true));
  }

  // GET请求封装
  Future<Response> get(String path, {Map<String, dynamic>? params}) async {
    try {
      return await dio.get(path, queryParameters: params);
    } on DioException catch (e) {
      rethrow;
    }
  }

  // POST请求封装
  Future<Response> post(String path, {Map<String, dynamic>? data}) async {
    try {
      return await dio.post(path, data: data);
    } on DioException catch (e) {
      rethrow;
    }
  }
}

四、数据模型定义
为了让网络响应数据更易使用,我们定义了 Post 数据模型,对 API 返回的数据进行序列化:

class Post {
  final int id;
  final String title;
  final String body;

  Post({required this.id, required this.title, required this.body});

  // 从JSON解析数据
  factory Post.fromJson(Map<String, dynamic> json) {
    return Post(
      id: json['id'],
      title: json['title'],
      body: json['body'],
    );
  }
}

五、完整网络数据列表页面实现
接下来我们实现一个 DataListPage,包含网络请求、数据展示、加载状态、错误处理与刷新能力:

import 'package:flutter/material.dart';
import 'package:dio/dio.dart';

class DataListPage extends StatefulWidget {
  const DataListPage({super.key});

  @override
  State<DataListPage> createState() => _DataListPageState();
}

class _DataListPageState extends State<DataListPage> {
  final NetworkService _networkService = NetworkService.instance;
  List<Post> posts = [];
  bool isLoading = false;
  String? errorMessage;

  @override
  void initState() {
    super.initState();
    fetchPosts();
  }

  // 拉取数据
  Future<void> fetchPosts() async {
    setState(() {
      isLoading = true;
      errorMessage = null;
    });
    try {
      final response = await _networkService.get('/posts');
      if (response.statusCode == 200) {
        List<dynamic> data = response.data;
        setState(() {
          posts = data.map((json) => Post.fromJson(json)).toList();
        });
      } else {
        setState(() {
          errorMessage = '请求失败,状态码:${response.statusCode}';
        });
      }
    } on DioException catch (e) {
      setState(() {
        errorMessage = '请求出错:${e.message}';
      });
    } finally {
      setState(() {
        isLoading = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('dio 网络请求示例'),
        actions: [
          IconButton(
            icon: const Icon(Icons.refresh),
            onPressed: fetchPosts,
          ),
        ],
      ),
      body: buildBody(),
    );
  }

  Widget buildBody() {
    if (isLoading) {
      return const Center(child: CircularProgressIndicator());
    }
    if (errorMessage != null) {
      return Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(errorMessage!),
            const SizedBox(height: 16),
            ElevatedButton(onPressed: fetchPosts, child: const Text('重试')),
          ],
        ),
      );
    }
    return ListView.builder(
      itemCount: posts.length,
      itemBuilder: (context, index) {
        final post = posts[index];
        return Card(
          margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
          child: Padding(
            padding: const EdgeInsets.all(16),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  'ID: ${post.id}',
                  style: const TextStyle(fontSize: 12, color: Colors.grey),
                ),
                const SizedBox(height: 8),
                Text(
                  post.title,
                  style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                ),
                const SizedBox(height: 8),
                Text(post.body),
              ],
            ),
          ),
        );
      },
    );
  }
}
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter 鸿蒙网络请求示例',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const DataListPage(),
    );
  }
}

六、鸿蒙设备运行验证
将项目编译并安装到鸿蒙设备后,应用成功运行,实现了以下效果:
1启动时自动加载网络数据,页面显示加载动画
2数据加载完成后,以卡片形式展示列表数据
3网络请求失败时,显示错误信息与重试按钮
4点击右上角刷新按钮,可重新发起请求
七、适配总结与注意事项
**1依赖兼容性:**dio 5.x 版本对 OpenHarmony 平台的兼容性良好,无需额外修改即可直接使用,避免了复杂的平台适配成本。
**2错误处理:**在鸿蒙设备上,网络环境与权限配置可能导致请求失败,建议统一捕获 DioException,并在界面上给用户明确的反馈。
**3网络权限:**在鸿蒙项目中,需确保已配置网络权限,否则会出现请求失败的问题。
4代码托管规范:本文项目代码已托管至 AtomGit 平台,仓库地址:https://atomgit.com/your-repo/flutter-oh-dio-demo,禁止使用 GitCode 相关链接。
八、后续扩展方向
基于当前的基础实现,还可以进一步扩展网络请求能力:
添加请求拦截器,统一添加 Token 等请求头
封装文件上传 / 下载功能
结合 dio 的 CancelToken 实现请求取消
实现网络请求缓存策略

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐