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

如何在Riverpod的AsyncNotifier的build方法中处理网络异常

解决Riverpod AsyncNotifier网络异常处理问题

你之前在build()中使用AsyncValue.guard出现语法错误,核心原因是AsyncValue.guard返回的是Future<AsyncValue<T>>,而AsyncNotifier的build()要求返回Future<T>,类型不匹配导致报错。以下是正确的异常处理实现方案:

1. 修正网络请求与异常捕获

首先完善_fetchTodo方法,处理网络连接异常、请求状态错误及JSON解析错误,同时修正http.get的参数格式(需传入Uri而非字符串):

Future<List<Todo>> _fetchTodo() async {
  try {
    // 修正:http.get需要传入Uri对象
    final response = await http.get(Uri.parse('api/todos'));
    
    // 检查响应状态码
    if (response.statusCode != 200) {
      throw Exception('请求失败,状态码:${response.statusCode}');
    }
    
    final todos = jsonDecode(response.body) as List<Map<String, dynamic>>;
    return todos.map((todo) => Todo.fromJson(todo)).toList();
  } on ClientException catch (e) {
    // 捕获无网络等连接异常
    throw Exception('网络连接失败:${e.message}');
  } catch (e) {
    // 捕获其他异常(如JSON解析错误)
    throw Exception('加载数据失败:$e');
  }
}

2. 正确实现build方法的异常处理

AsyncNotifier会自动将build()返回的Future转换为AsyncValue状态(加载/成功/错误),因此你可以直接返回_fetchTodo(),异常会被自动捕获并转为AsyncValue.error:

@override
Future<List<Todo>> build() async {
  return _fetchTodo();
}

如果需要在build()中主动处理异常(比如记录日志),可以用AsyncValue.guard配合类型转换:

@override
Future<List<Todo>> build() async {
  final asyncValue = await AsyncValue.guard(_fetchTodo);
  
  if (asyncValue.hasError) {
    // 可选:添加日志记录等自定义操作
    print('加载待办列表出错:${asyncValue.error}');
    // 重新抛出异常,让AsyncNotifier将state设置为错误状态
    rethrow;
  }
  
  return asyncValue.requireValue;
}

3. UI层处理异常状态

必须在UI层使用AsyncValue.when处理三种状态,避免直接访问state.value导致崩溃:

Consumer(
  builder: (context, ref, child) {
    final todosState = ref.watch(asyncTodosProvider);
    
    return todosState.when(
      loading: () => const Center(child: CircularProgressIndicator()),
      error: (error, stackTrace) => Center(child: Text('出错了:$error')),
      data: (todos) => ListView.builder(
        itemCount: todos.length,
        itemBuilder: (context, index) {
          final todo = todos[index];
          return ListTile(
            title: Text(todo.description),
            leading: Checkbox(value: todo.completed, onChanged: (_) {}),
          );
        },
      ),
    );
  },
)

完整修改后的AsyncTodosNotifier代码

class AsyncTodosNotifier extends AsyncNotifier<List<Todo>> {
  Future<List<Todo>> _fetchTodo() async {
    try {
      final response = await http.get(Uri.parse('api/todos'));
      if (response.statusCode != 200) {
        throw Exception('请求失败,状态码:${response.statusCode}');
      }
      final todos = jsonDecode(response.body) as List<Map<String, dynamic>>;
      return todos.map((todo) => Todo.fromJson(todo)).toList();
    } on ClientException catch (e) {
      throw Exception('网络连接失败:${e.message}');
    } catch (e) {
      throw Exception('加载数据失败:$e');
    }
  }

  @override
  Future<List<Todo>> build() async {
    return _fetchTodo();
  }

  Future<void> addTodo(Todo todo) async {
    state = const AsyncValue.loading();
    state = await AsyncValue.guard(() async {
      await http.post(Uri.parse('api/todos'), body: todo.toJson());
      return _fetchTodo();
    });
  }
}

final asyncTodosProvider = AsyncNotifierProvider<AsyncTodosNotifier, List<Todo>>(() {
  return AsyncTodosNotifier();
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 10:55:23