Flutter中如何保存JSON API请求数据?类电商应用如何实现商品收藏并在另一页展示?
Hey there! Let's walk through how to build the favorite feature for your e-commerce app and handle saving JSON API data in Flutter. I'll break this down into actionable steps with code examples you can reuse directly.
第一步:把API返回的JSON转为Dart模型类
First, you'll want to convert the raw JSON from your API into strongly-typed Dart objects—this makes data handling safer and more maintainable. Suppose your product JSON looks like this:
{ "id": 1, "name": "Wireless Headphones", "price": 99.99, "imageUrl": "https://example.com/headphones.jpg", "description": "Noise-cancelling over-ear headphones" }
Use the json_serializable package to generate serialization code. First add dependencies to pubspec.yaml:
dependencies: json_annotation: ^4.8.1 dev_dependencies: build_runner: ^2.4.4 json_serializable: ^6.7.0
Then create your product model:
import 'package:json_annotation/json_annotation.dart'; part 'product.g.dart'; @JsonSerializable() class Product { final int id; final String name; final double price; final String imageUrl; final String description; Product({ required this.id, required this.name, required this.price, required this.imageUrl, required this.description, }); // Convert JSON to Product object factory Product.fromJson(Map<String, dynamic> json) => _$ProductFromJson(json); // Convert Product object to JSON Map<String, dynamic> toJson() => _$ProductToJson(this); }
Run flutter pub run build_runner build to generate the serialization boilerplate—now you can easily convert between JSON and Dart objects.
第二步:选择合适的本地存储方案
Based on your needs (saving a list of favorite products), here are the most common and practical options:
方案1:SharedPreferences(适合小量数据)
If your favorite list won't grow too large (e.g., dozens of items), SharedPreferences is a simple choice—it stores basic types like strings. We'll serialize the product list into a JSON string for storage.
Create a storage service class:
import 'package:shared_preferences/shared_preferences.dart'; import 'dart:convert'; import 'product.dart'; class FavoriteStorage { static const String _favoritesKey = 'favorite_products'; // Add a product to favorites Future<void> addFavorite(Product product) async { final prefs = await SharedPreferences.getInstance(); List<String> favorites = prefs.getStringList(_favoritesKey) ?? []; // Avoid duplicates bool isAlreadyFavorite = favorites.any((item) { return Product.fromJson(jsonDecode(item)).id == product.id; }); if (!isAlreadyFavorite) { favorites.add(jsonEncode(product.toJson())); await prefs.setStringList(_favoritesKey, favorites); } } // Remove a product from favorites Future<void> removeFavorite(int productId) async { final prefs = await SharedPreferences.getInstance(); List<String> favorites = prefs.getStringList(_favoritesKey) ?? []; favorites.removeWhere((item) { return Product.fromJson(jsonDecode(item)).id == productId; }); await prefs.setStringList(_favoritesKey, favorites); } // Get all favorite products Future<List<Product>> getFavorites() async { final prefs = await SharedPreferences.getInstance(); List<String> favorites = prefs.getStringList(_favoritesKey) ?? []; return favorites.map((item) => Product.fromJson(jsonDecode(item))).toList(); } // Check if a product is already favorited Future<bool> isFavorite(int productId) async { final prefs = await SharedPreferences.getInstance(); List<String> favorites = prefs.getStringList(_favoritesKey) ?? []; return favorites.any((item) { return Product.fromJson(jsonDecode(item)).id == productId; }); } }
方案2:Hive(适合结构化数据,操作更便捷)
Hive is a lightweight NoSQL database that lets you store Dart objects directly (no manual JSON serialization needed). It's faster than SharedPreferences and great for medium-sized datasets.
Add dependencies first:
dependencies: hive: ^2.2.3 hive_flutter: ^1.1.0 dev_dependencies: hive_generator: ^1.1.5 build_runner: ^2.4.4
Initialize Hive in your main() function and register the adapter:
void main() async { await Hive.initFlutter(); Hive.registerAdapter(ProductAdapter()); // Generated adapter runApp(MyApp()); }
Update your Product model to work with Hive:
import 'package:hive/hive.dart'; part 'product.g.dart'; @HiveType(typeId: 0) // Unique ID for this object type class Product extends HiveObject { @HiveField(0) final int id; @HiveField(1) final String name; @HiveField(2) final double price; @HiveField(3) final String imageUrl; @HiveField(4) final String description; Product({ required this.id, required this.name, required this.price, required this.imageUrl, required this.description, }); }
Run flutter pub run build_runner build to generate the adapter, then create the Hive storage service:
import 'package:hive/hive.dart'; import 'product.dart'; class FavoriteStorage { late Box<Product> _favoriteBox; Future<void> init() async { _favoriteBox = await Hive.openBox<Product>('favorite_products'); } Future<void> addFavorite(Product product) async { if (!_favoriteBox.containsKey(product.id)) { await _favoriteBox.put(product.id, product); } } Future<void> removeFavorite(int productId) async { await _favoriteBox.delete(productId); } List<Product> getFavorites() { return _favoriteBox.values.toList(); } bool isFavorite(int productId) { return _favoriteBox.containsKey(productId); } }
Don't forget to call await FavoriteStorage().init() when your app starts.
方案3:SQFlite(适合复杂查询场景)
If you need advanced filtering, sorting, or have a large dataset, SQFlite (Flutter's SQLite wrapper) is the way to go. It's more verbose but offers full SQL capabilities.
Add dependencies:
dependencies: sqflite: ^2.3.0 path: ^1.8.3
Create a database helper class:
import 'package:sqflite/sqflite.dart'; import 'package:path/path.dart'; import 'product.dart'; class DatabaseHelper { static final DatabaseHelper _instance = DatabaseHelper._internal(); factory DatabaseHelper() => _instance; DatabaseHelper._internal(); static Database? _database; Future<Database> get database async { if (_database != null) return _database!; _database = await _initDatabase(); return _database!; } Future<Database> _initDatabase() async { String path = join(await getDatabasesPath(), 'ecommerce.db'); return await openDatabase( path, version: 1, onCreate: (db, version) async { await db.execute(''' CREATE TABLE products( id INTEGER PRIMARY KEY, name TEXT, price REAL, imageUrl TEXT, description TEXT ) '''); }, ); } Future<void> addFavorite(Product product) async { final db = await database; await db.insert( 'products', product.toJson(), conflictAlgorithm: ConflictAlgorithm.replace, ); } Future<void> removeFavorite(int productId) async { final db = await database; await db.delete( 'products', where: 'id = ?', whereArgs: [productId], ); } Future<List<Product>> getFavorites() async { final db = await database; final List<Map<String, dynamic>> maps = await db.query('products'); return List.generate(maps.length, (i) { return Product.fromJson(maps[i]); }); } Future<bool> isFavorite(int productId) async { final db = await database; final List<Map<String, dynamic>> maps = await db.query( 'products', where: 'id = ?', whereArgs: [productId], ); return maps.isNotEmpty; } }
第三步:实现收藏图标点击逻辑
Add a favorite icon to your product list item or detail page, with toggle functionality:
import 'package:flutter/material.dart'; import 'product.dart'; import 'favorite_storage.dart'; class ProductItem extends StatefulWidget { final Product product; const ProductItem({super.key, required this.product}); @override State<ProductItem> createState() => _ProductItemState(); } class _ProductItemState extends State<ProductItem> { late FavoriteStorage _storage; bool _isFavorite = false; @override void initState() { super.initState(); _storage = FavoriteStorage(); _checkFavoriteStatus(); } Future<void> _checkFavoriteStatus() async { bool status = await _storage.isFavorite(widget.product.id); setState(() { _isFavorite = status; }); } Future<void> _toggleFavorite() async { if (_isFavorite) { await _storage.removeFavorite(widget.product.id); } else { await _storage.addFavorite(widget.product); } setState(() { _isFavorite = !_isFavorite; }); } @override Widget build(BuildContext context) { return Card( child: Column( children: [ Image.network(widget.product.imageUrl, height: 150, fit: BoxFit.cover), Padding( padding: const EdgeInsets.all(8.0), child: Text(widget.product.name, style: const TextStyle(fontSize: 16)), ), Text('\$${widget.product.price.toStringAsFixed(2)}'), IconButton( icon: Icon( _isFavorite ? Icons.favorite : Icons.favorite_border, color: _isFavorite ? Colors.red : null, ), onPressed: _toggleFavorite, ), ], ), ); } }
第四步:展示收藏列表页面
Create a page to load and display all favorite products:
import 'package:flutter/material.dart'; import 'favorite_storage.dart'; import 'product.dart'; import 'product_item.dart'; class FavoritesPage extends StatefulWidget { const FavoritesPage({super.key}); @override State<FavoritesPage> createState() => _FavoritesPageState(); } class _FavoritesPageState extends State<FavoritesPage> { late FavoriteStorage _storage; List<Product> _favoriteProducts = []; @override void initState() { super.initState(); _storage = FavoriteStorage(); _loadFavorites(); } Future<void> _loadFavorites() async { List<Product> products = await _storage.getFavorites(); setState(() { _favoriteProducts = products; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('My Favorites')), body: _favoriteProducts.isEmpty ? const Center(child: Text('No favorite products yet')) : GridView.builder( padding: const EdgeInsets.all(8), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 8, mainAxisSpacing: 8, childAspectRatio: 0.75, ), itemCount: _favoriteProducts.length, itemBuilder: (context, index) { return ProductItem(product: _favoriteProducts[index]); }, ), ); } }
快速方案选择指南
- SharedPreferences: Best for small datasets (dozens of items), simplest implementation.
- Hive: Best for structured objects, easy to use, better performance than SharedPreferences.
- SQFlite: Best for large datasets or when you need advanced SQL queries.
No matter which option you pick, the core flow is the same: serialize and save product data when the user taps favorite, then deserialize and display it in the favorites page.
内容的提问来源于stack exchange,提问作者EDMGL

