第7章:网络请求与本地存储
现代 App 大多数都依赖远程接口(API)获取数据并在本地缓存用户状态或持久化数据。本章将教你如何在 Flutter 中完成这些操作。
一、网络请求(使用 http 库)
1. 添加依赖
dependencies:
http: ^0.13.0
2. 发起 GET 请求
import 'package:http/http.dart' as http;
import 'dart:convert';
Future<void> fetchData() async {
final url = Uri.parse('https://jsonplaceholder.typicode.com/posts/1');
final response = await http.get(url);
if (response.statusCode == 200) {
final data = json.decode(response.body);
print(data['title']);
} else {
throw Exception('Failed to load data');
}
}
3. 发起 POST 请求
Future<void> submitData() async {
final url = Uri.parse('https://example.com/api');
final response = await http.post(
url,
headers: {'Content-Type': 'application/json'},
body: json.encode({'name': 'Eric', 'age': 25}),
);
if (response.statusCode == 200) {
print('Submitted successfully');
}
}
4. 解析 JSON 为模型类(推荐)
使用 Dart 类解析 JSON,结构更清晰:
class Post {
final int id;
final String title;
Post({required this.id, required this.title});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
id: json['id'],
title: json['title'],
);
}
}
使用:
final data = json.decode(response.body);
Post post = Post.fromJson(data);
二、本地存储(轻量级持久化)
1. 使用 SharedPreferences(用于保存小型键值数据)
添加依赖
dependencies:
shared_preferences: ^2.0.0
存储数据
final prefs = await SharedPreferences.getInstance();
prefs.setInt('counter', 10);
prefs.setString('username', 'Eric');
读取数据
final prefs = await SharedPreferences.getInstance();
int counter = prefs.getInt('counter') ?? 0;
String? username = prefs.getString('username');
2. 使用 SQLite 数据库(适合结构化数据)
添加依赖
dependencies:
sqflite: ^2.0.0
path: ^1.8.0
初始化数据库
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
Future<Database> initDB() async {
final path = join(await getDatabasesPath(), 'demo.db');
return openDatabase(
path,
version: 1,
onCreate: (db, version) {
return db.execute(
'CREATE TABLE users(id INTEGER PRIMARY KEY, name TEXT)',
);
},
);
}
插入数据
Future<void> insertUser(Database db, String name) async {
await db.insert(
'users',
{'name': name},
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
查询数据
Future<List<Map<String, dynamic>>> getUsers(Database db) async {
return await db.query('users');
}
三、常见问题解析
❗ 问题 1:网络请求报错(SocketException、CORS)
可能原因:
- Android 模拟器未连接网络
- 请求使用了
http://,应改为https:// - 请求地址跨域(Web 平台)
解决方案:
-
Android:在
AndroidManifest.xml中添加网络权限<uses-permission android:name="android.permission.INTERNET" /> -
Web 跨域:需服务端支持 CORS,或使用代理
❗ 问题 2:json.decode 报错
常见错误:
- 数据为空或格式不对(返回非 JSON)
- 接收的是数组而非对象(需区分
List与Map)
示例解决:
final List data = json.decode(response.body); // 若返回数组
❗ 问题 3:SharedPreferences 读取不到值
检查点:
- 写入后是否忘记
await保存 - 使用了不同的 key 名称
- 读取前是否执行过
SharedPreferences.getInstance()
❗ 问题 4:SQLite 插入失败或查询不到数据
检查点:
- 数据库路径是否正确(推荐使用
join) - 字段名是否正确
- 是否使用了正确的
async/await流程