面试题答案
一键面试将http请求与状态管理有效结合
- 创建数据模型
- 首先,定义商品数据的模型类。例如,创建一个
Product
类来表示商品信息:
class Product { final int id; final String name; final double price; // 其他商品属性 Product({ required this.id, required this.name, required this.price, }); factory Product.fromJson(Map<String, dynamic> json) { return Product( id: json['id'], name: json['name'], price: json['price'].toDouble(), ); } }
- 首先,定义商品数据的模型类。例如,创建一个
- 定义Provider状态管理类
- 创建一个继承自
ChangeNotifier
的ProductProvider
类。这个类负责管理商品相关的状态,包括商品列表、加载状态等。
import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; class ProductProvider extends ChangeNotifier { List<Product> _products = []; bool _isLoading = false; List<Product> get products => _products; bool get isLoading => _isLoading; Future<void> fetchProducts() async { _isLoading = true; notifyListeners(); try { final response = await http.get(Uri.parse('your - api - url/products')); if (response.statusCode == 200) { final List<dynamic> jsonList = json.decode(response.body); _products = jsonList.map((json) => Product.fromJson(json)).toList(); } else { throw Exception('Failed to load products'); } } catch (e) { print('Error fetching products: $e'); } finally { _isLoading = false; notifyListeners(); } } Future<void> updateProduct(Product product) async { _isLoading = true; notifyListeners(); try { final response = await http.put( Uri.parse('your - api - url/products/${product.id}'), headers: {'Content - Type': 'application/json'}, body: json.encode({ 'name': product.name, 'price': product.price, }), ); if (response.statusCode == 200) { // 假设更新成功后重新获取所有商品 await fetchProducts(); } else { throw Exception('Failed to update product'); } } catch (e) { print('Error updating product: $e'); } finally { _isLoading = false; notifyListeners(); } } }
- 创建一个继承自
- 在Widget中使用Provider
- 在
main.dart
中,将ProductProvider
提供给整个应用:
void main() { runApp( ChangeNotifierProvider( create: (context) => ProductProvider(), child: MyApp(), ), ); }
- 在需要显示商品列表或进行更新操作的Widget中,通过
Provider.of
获取ProductProvider
实例,并根据状态进行界面更新。例如,在商品列表页面:
class ProductListPage extends StatelessWidget { @override Widget build(BuildContext context) { final productProvider = Provider.of<ProductProvider>(context); return Scaffold( appBar: AppBar( title: Text('Product List'), ), body: productProvider.isLoading ? Center(child: CircularProgressIndicator()) : ListView.builder( itemCount: productProvider.products.length, itemBuilder: (context, index) { final product = productProvider.products[index]; return ListTile( title: Text(product.name), subtitle: Text('\$${product.price}'), // 可以添加更新等操作按钮 ); }, ), floatingActionButton: FloatingActionButton( onPressed: () async { await productProvider.fetchProducts(); }, child: Icon(Icons.refresh), ), ); } }
- 在
处理并发请求带来的状态冲突问题
- 加锁机制
- 在
ProductProvider
类中,可以使用Lock
类(来自dart:async
库)来处理并发请求。例如,在fetchProducts
和updateProduct
方法中:
import 'dart:async'; class ProductProvider extends ChangeNotifier { //... final Lock _lock = Lock(); Future<void> fetchProducts() async { await _lock.synchronized(() async { _isLoading = true; notifyListeners(); try { final response = await http.get(Uri.parse('your - api - url/products')); if (response.statusCode == 200) { final List<dynamic> jsonList = json.decode(response.body); _products = jsonList.map((json) => Product.fromJson(json)).toList(); } else { throw Exception('Failed to load products'); } } catch (e) { print('Error fetching products: $e'); } finally { _isLoading = false; notifyListeners(); } }); } Future<void> updateProduct(Product product) async { await _lock.synchronized(() async { _isLoading = true; notifyListeners(); try { final response = await http.put( Uri.parse('your - api - url/products/${product.id}'), headers: {'Content - Type': 'application/json'}, body: json.encode({ 'name': product.name, 'price': product.price, }), ); if (response.statusCode == 200) { await fetchProducts(); } else { throw Exception('Failed to update product'); } } catch (e) { print('Error updating product: $e'); } finally { _isLoading = false; notifyListeners(); } }); } }
- 在
- 版本控制
- 在API设计中,可以引入版本号。每次数据更新时,版本号递增。
- 在
ProductProvider
中,保存当前数据的版本号。当进行请求时,将版本号发送到服务器。如果服务器发现版本号不一致,说明数据在其他请求过程中已被更新,返回相应的错误信息。客户端根据错误信息决定是否重新获取数据。例如,在updateProduct
方法中:
Future<void> updateProduct(Product product) async { _isLoading = true; notifyListeners(); try { final response = await http.put( Uri.parse('your - api - url/products/${product.id}'), headers: { 'Content - Type': 'application/json', 'Version': _version.toString() // 假设 _version 是保存版本号的变量 }, body: json.encode({ 'name': product.name, 'price': product.price, }), ); if (response.statusCode == 200) { // 更新成功,获取新的版本号并更新本地版本号 final newVersion = int.parse(response.headers['version']!); _version = newVersion; await fetchProducts(); } else if (response.statusCode == 409) { // 版本冲突错误 print('Version conflict, please refresh data'); await fetchProducts(); } else { throw Exception('Failed to update product'); } } catch (e) { print('Error updating product: $e'); } finally { _isLoading = false; notifyListeners(); } }