Flutter 鸿蒙新手实战:网络请求 + 列表展示,一键跑通鸿蒙虚拟机
🚀 Flutter 鸿蒙新手实战:网络请求 + 列表展示,一键跑通鸿蒙虚拟机
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrosplatform.csdn.net
哈喽各位~ 我是计算机专业大一新生,这是我的第一个鸿蒙 Flutter 实战作业📒,全程新手友好、代码可直接复制、能在鸿蒙虚拟机完美运行!
本文带大家从零搞定「dio 网络库集成 + JSON 数据解析 + 列表渲染 + 鸿蒙适配」全流程,没有冗余废话,跟着做就能出成果✨
⚙️ 前置环境准备
DevEco Studio 4.0+(内置鸿蒙 SDK、模拟器)
适配 OpenHarmony 的 Flutter SDK 3.16+
已启动的虚拟鸿蒙主机(OpenHarmony 3.2+)
能正常联网的开发环境
📂 极简项目结构
分层清晰,新手不混乱,完全符合 Flutter 开发规范:
demo1/
├── ohos/ # 鸿蒙平台专属配置
├── lib/
│ ├── main.dart # 应用入口+页面UI
│ ├── models/post.dart # 数据模型(JSON解析)
│ └── services/api_service.dart # 网络请求封装
└── pubspec.yaml # 项目依赖配置
💻 核心功能一步步实现
- 📦 集成 dio 三方网络库
dio 是 Flutter 生态顶流网络库,已完美适配鸿蒙系统,也是本次征文要求的「三方库鸿蒙化实践」核心内容~
打开项目根目录的pubspec.yaml,添加依赖:
dependencies:
flutter:
sdk: flutter
dio: ^5.4.0 # 鸿蒙适配稳定版
保存后,终端执行 flutter pub get 拉取依赖,一步搞定✅
- 🌐 封装网络请求服务
在lib/services/api_service.dart中,封装统一的网络请求,单例模式 + 全局配置,新手直接复制就能用:
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
class ApiService {
// 单例模式,全局唯一实例
static final ApiService _instance = ApiService._internal();
factory ApiService() => _instance;
ApiService._internal();
static Dio? _dio;
// 懒加载初始化dio
static Dio get dio {
_dio ??= _initDio();
return _dio!;
}
// 全局dio配置
static Dio _initDio() {
final dio = Dio(
BaseOptions(
baseUrl: "https://jsonplaceholder.typicode.com/",
connectTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 10),
),
);
// 日志拦截器,开发调试超方便
dio.interceptors.add(LogInterceptor(responseBody: true));
return dio;
}
// 获取帖子列表接口
static Future<List<dynamic>> getPostList() async {
final response = await dio.get("/posts");
return response.data;
}
}
- 🧩 定义数据模型,JSON 一键解析
把接口返回的无结构 JSON,转成强类型的 Dart 对象,避免写错字段导致翻车!
在lib/models/post.dart中写入:
class Post {
final int id;
final String title;
final String body;
Post({required this.id, required this.title, required this.body});
// JSON转Post对象
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
id: json['id'] ?? 0,
title: json['title'] ?? '无标题',
body: json['body'] ?? '无内容',
);
}
// 批量解析列表数据
static List<Post> fromJsonList(List<dynamic> jsonList) {
return jsonList.map((json) => Post.fromJson(json)).toList();
}
}
- 🎨 主页面实现:列表 + 全状态管理
修改lib/main.dart,完整实现加载中 / 加载失败 / 加载成功三种状态,卡片式列表美观又好懂:
import 'package:flutter/material.dart';
import 'models/post.dart';
import 'services/api_service.dart';
// 应用入口
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: '鸿蒙Flutter实战',
theme: ThemeData(primarySwatch: Colors.purple),
home: const PostListPage(),
debugShowCheckedModeBanner: false,
);
}
}
// 帖子列表页面
class PostListPage extends StatefulWidget {
const PostListPage({super.key});
State<PostListPage> createState() => _PostListPageState();
}
class _PostListPageState extends State<PostListPage> {
List<Post> postList = [];
bool isLoading = true;
String? errorMsg;
void initState() {
super.initState();
// 页面启动时加载数据
loadData();
}
// 核心:加载网络数据
Future<void> loadData() async {
setState(() {
isLoading = true;
errorMsg = null;
});
try {
final jsonData = await ApiService.getPostList();
setState(() {
postList = Post.fromJsonList(jsonData);
isLoading = false;
});
} catch (e) {
setState(() {
errorMsg = e.toString();
isLoading = false;
});
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("开发者社区"), centerTitle: true),
body: buildBody(),
// 悬浮刷新按钮
floatingActionButton: FloatingActionButton(
onPressed: loadData,
child: const Icon(Icons.refresh),
),
);
}
// 动态渲染页面状态
Widget buildBody() {
// 1. 加载中状态⏳
if (isLoading) {
return const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(),
SizedBox(height: 16),
Text("数据加载中...", style: TextStyle(color: Colors.grey)),
],
),
);
}
// 2. 加载失败状态❌
if (errorMsg != null) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, color: Colors.red, size: 48),
const SizedBox(height: 16),
Text(errorMsg!, textAlign: TextAlign.center),
const SizedBox(height: 20),
ElevatedButton(onPressed: loadData, child: const Text("点击重试")),
],
),
);
}
// 3. 加载成功状态✅ 列表展示
return ListView.builder(
padding: const EdgeInsets.all(12),
itemCount: postList.length,
itemBuilder: (context, index) {
final post = postList[index];
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
post.title,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
maxLines: 2,
),
const SizedBox(height: 8),
Text(
post.body,
style: const TextStyle(color: Colors.grey),
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 8),
Align(
alignment: Alignment.bottomRight,
child: Text("帖子ID:${post.id}", style: const TextStyle(fontSize: 12, color: Colors.grey)),
),
],
),
),
),
);
},
);
}
}
🔧 鸿蒙专属适配(必做!不然网络直接翻车)
鸿蒙系统对应用权限管控超严格,想要访问网络,必须配置网络权限,否则所有请求都会被系统拦截!
打开 ohos/entry/src/main/module.json5,在requestPermissions数组中添加以下配置:
{
"name": "ohos.permission.INTERNET",
"reason": "应用需要访问网络获取帖子数据",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
保存文件,权限配置就搞定啦✅
📱 一键运行到鸿蒙虚拟机
- 构建鸿蒙 HAP 安装包
HAP 是鸿蒙应用的安装包格式,终端进入项目的ohos目录,执行构建命令:
hvigorw assembleHap -p product=default -p buildMode=debug
终端出现BUILD SUCCESS,就是构建成功啦🎉
2. 安装应用到虚拟鸿蒙主机
hdc install -r entry/build/default/outputs/default/entry-default-unsigned.hap
- 启动应用
hdc shell aa start -a EntryAbility -b com.example.demo1
搞定!现在你的虚拟鸿蒙主机上,已经能看到应用完美运行,列表正常加载、刷新功能丝滑可用✨
运行效果截图

⚠️ 新手必看踩坑指南
✨ 学习总结
通过这次实战,我这个大一新生从零搞定了:
✅ Flutter 三方库的集成与鸿蒙适配
✅ dio 网络请求封装与 JSON 数据解析
✅ 鸿蒙应用权限配置与 HAP 包构建
✅ 列表页面的状态管理与 UI 渲染
✅ 应用在鸿蒙虚拟机的全流程运行
全程没有复杂晦涩的概念,新手跟着做就能复现,也完美完成了老师布置的作业~ 后续我也会继续分享鸿蒙 Flutter 的新手实战内容,和大家一起学习进步💪
更多推荐



所有评论(0)