You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中FutureProvider取数据到GridView遇连接拒绝错误及优化咨询

「Connection refused」错误排查

先从这几个核心方向排查问题:

  • API地址与网络可达性:
    • 若后端是本地服务,Android模拟器不能直接用localhost,要替换成10.0.2.2;真机需和后端在同一局域网,用电脑的局域网IP(比如192.168.1.100)。
    • 确认后端服务正在运行,端口没被防火墙拦截,先用浏览器或Postman测试目标URL能否正常返回数据。
  • 项目网络权限:
    • Android:在android/app/src/main/AndroidManifest.xml里添加<uses-permission android:name="android.permission.INTERNET"/>。
    • iOS:如果用的是HTTP请求,要在Info.plist中配置NSAppTransportSecurity,允许非HTTPS请求。
  • 请求代码细节:
    • 检查请求方法(GET/POST)、请求头是否符合API要求,比如API要求Content-Type: application/json但代码里没添加。
    • 举个常见的仓库代码错误示例:
      class FakeProductRepository {
        Future<List<Product>> getProducts() async {
          // 错误:模拟器无法访问localhost
          final response = await http.get(Uri.parse('http://localhost:3000/products'));
          if (response.statusCode == 200) {
            final data = jsonDecode(response.body)['data'] as List;
            return data.map((e) => Product.fromJson(e)).toList();
          } else {
            throw Exception('Failed to load products');
          }
        }
      }
      
      把localhost换成10.0.2.2(模拟器)或局域网IP即可解决。
多请求场景下的Provider封装优化

不用每个请求都单独创建FutureProvider,推荐这几种更高效的封装方案:

1. 用Family实现参数化请求

如果请求需要传入动态参数(比如按分类ID获取商品),用FutureProvider.family复用请求逻辑:

// 定义带参数的Provider
final categoryProductsProvider = FutureProvider.family<List<Product>, int>((ref, categoryId) {
  return ref.watch(productRepositoryProvider).getProductsByCategory(categoryId);
});

// 组件中使用时传入参数
ref.watch(categoryProductsProvider(1)); // 获取分类ID为1的商品列表

2. 基于Repository封装,配合AsyncValue管理多请求

把所有请求逻辑集中在Repository里,通过单个Provider提供实例,组件中直接调用方法并结合AsyncValue统一处理状态:

// 提供Repository实例
final productRepositoryProvider = Provider<FakeProductRepository>((ref) {
  return FakeProductRepository();
});

// 组件中调用多个请求
final repo = ref.watch(productRepositoryProvider);
// 用AsyncValue统一处理加载/错误/数据状态
final allProductsAsync = AsyncValue.guard(() => repo.getProducts());
final hotProductsAsync = AsyncValue.guard(() => repo.getHotProducts());

3. 用StateNotifier管理多请求状态(复杂场景首选)

如果需要缓存数据、处理多个请求的状态联动,用StateNotifier封装所有请求状态:

// 定义状态类,包含多个请求的状态
class ProductState extends Equatable {
  final AsyncValue<List<Product>> allProducts;
  final AsyncValue<List<Product>> hotProducts;

  const ProductState({
    this.allProducts = const AsyncValue.loading(),
    this.hotProducts = const AsyncValue.loading(),
  });

  ProductState copyWith({
    AsyncValue<List<Product>>? allProducts,
    AsyncValue<List<Product>>? hotProducts,
  }) => ProductState(
    allProducts: allProducts ?? this.allProducts,
    hotProducts: hotProducts ?? this.hotProducts,
  );

  @override
  List<Object?> get props => [allProducts, hotProducts];
}

// 状态管理器
class ProductNotifier extends StateNotifier<ProductState> {
  final FakeProductRepository _repo;

  ProductNotifier(this._repo) : super(const ProductState());

  // 获取全部商品
  Future<void> fetchAllProducts() async {
    state = state.copyWith(allProducts: const AsyncValue.loading());
    try {
      final products = await _repo.getProducts();
      state = state.copyWith(allProducts: AsyncValue.data(products));
    } catch (e, stack) {
      state = state.copyWith(allProducts: AsyncValue.error(e, stack));
    }
  }

  // 获取热门商品
  Future<void> fetchHotProducts() async {
    state = state.copyWith(hotProducts: const AsyncValue.loading());
    try {
      final products = await _repo.getHotProducts();
      state = state.copyWith(hotProducts: AsyncValue.data(products));
    } catch (e, stack) {
      state = state.copyWith(hotProducts: AsyncValue.error(e, stack));
    }
  }
}

// 定义Provider
final productNotifierProvider = StateNotifierProvider<ProductNotifier, ProductState>((ref) {
  final repo = ref.watch(productRepositoryProvider);
  final notifier = ProductNotifier(repo);
  notifier.fetchAllProducts(); // 初始化加载数据
  return notifier;
});

// 组件中使用
final productState = ref.watch(productNotifierProvider);

// 渲染全部商品列表
productState.allProducts.when(
  loading: () => const CircularProgressIndicator(),
  error: (e, _) => Text('加载失败:$e'),
  data: (products) => GridView.builder(
    itemCount: products.length,
    gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
    itemBuilder: (context, index) => ProductCard(product: products[index]),
  ),
);

4. AsyncNotifier(Riverpod 2.0+ 简洁方案)

Riverpod 2.0的AsyncNotifier可以更简洁地处理异步状态,同时支持单个和额外请求:

final allProductsProvider = AsyncNotifierProvider<ProductsNotifier, List<Product>>(() {
  return ProductsNotifier();
});

class ProductsNotifier extends AsyncNotifier<List<Product>> {
  late final FakeProductRepository _repo;

  @override
  Future<List<Product>> build() async {
    _repo = ref.watch(productRepositoryProvider);
    return _repo.getProducts(); // 初始化加载数据
  }

  // 刷新全部商品
  Future<void> refresh() async {
    state = const AsyncValue.loading();
    state = AsyncValue.data(await _repo.getProducts());
  }

  // 获取分类商品(额外请求)
  Future<List<Product>> getCategoryProducts(int categoryId) async {
    return _repo.getProductsByCategory(categoryId);
  }
}

// 组件中使用
final allProducts = ref.watch(allProductsProvider);
// 调用额外请求
final categoryProducts = await ref.read(allProductsProvider.notifier).getCategoryProducts(1);

内容的提问来源于stack exchange,提问作者Mohammed M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 00:42:42