这就是我目前正在努力实现的目标:
我想使用
intl
包显示不同的错误消息,它使用 BuildContext
来了解用户语言。因此我想在 Widget 中处理异常,以便我可以用适当的语言显示它们。
我已经实现了我的代码如下:
我的问题是,如果我尝试通过构建一个捕获异常的未来来重用异常,那么无论如何都会执行使查询的原始函数。
为了说明这个问题,我写了一个包含所有这些组件的最小示例:
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:http/io_client.dart' as http;
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
///
/// CUSTOM EXCEPTION
///
class CustomTimeoutException implements Exception {}
///
/// SERVICE
///
class DemoService {
/// Return the client with a set timeout
http.IOClient _client() {
final ioClient = HttpClient();
ioClient.connectionTimeout = const Duration(seconds: 5);
return http.IOClient(ioClient);
}
/// Fetch all items of the inventory
Future<dynamic> fetchAllItems() async {
const String url = "http://10.0.2.2:8081";
http.Response response;
try {
response = await _client().get(Uri.parse(url));
} on SocketException {
print("Timeout reaching the server");
throw CustomTimeoutException();
}
if (response.statusCode != 200) {
print("Error fetching all data. ${response.statusCode}");
throw Exception("Error trying to fetch. (${response.statusCode})");
}
return response.body;
}
}
///
/// PROVIDER
///
class DemoProvider extends ChangeNotifier {
final List<String> _items = [];
bool _isLoading = false;
List<String> get items => _items;
bool get isLoading => _isLoading;
/// Download the list of items
Future<void> fetchAllItems(bool refresh) async {
// Fetch
_isLoading = true;
notifyListeners();
try {
final response = await DemoService().fetchAllItems();
_items.addAll(response['items']);
_isLoading = false;
notifyListeners();
} on CustomTimeoutException {
_isLoading = false;
notifyListeners();
rethrow;
}
}
}
///
/// MAIN WIDGET
///
class DemoWidget extends StatefulWidget {
const DemoWidget({Key? key}) : super(key: key);
@override
State<DemoWidget> createState() => _DemoWidgetState();
}
class _DemoWidgetState extends State<DemoWidget> {
String? _error;
void _onTimeOutError(dynamic _) {
setState(() {
_error =
"There was a timeout :( ${_.toString()}"; // TODO: Get translation from context
});
}
Future<void> _fetchAllItems(bool refresh) async {
setState(() {
_error = null;
});
return context
.read<DemoProvider>()
.fetchAllItems(refresh)
.catchError(_onTimeOutError, test: (e) => e is CustomTimeoutException);
}
void _onPressed() {
print("Test");
_fetchAllItems(true).then(
(value) => print("Do something after fetch"),
);
}
void _onPressed2() {
print("Test2");
_fetchAllItems(true).then(
(value) => print("Do another thing after fetch"),
);
}
@override
Widget build(BuildContext context) {
return Consumer<DemoProvider>(builder: (ctx, provider, _) {
return provider.isLoading
? const Center(
child: CircularProgressIndicator(),
)
: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: _onPressed,
child: const Text("Test"),
),
ElevatedButton(
onPressed: _onPressed2,
child: const Text("Test2"),
),
if (_error != null) Text(_error!)
],
),
);
});
}
}
///
/// APP
///
class DemoApp extends StatefulWidget {
const DemoApp({super.key});
@override
State<DemoApp> createState() => _DemoApp();
}
class _DemoApp extends State<DemoApp> {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => DemoProvider()),
],
child: const MaterialApp(
title: "Demo Application",
home: Scaffold(
body: DemoWidget(),
),
),
);
}
}
void main() {
runApp(DemoApp());
}
我希望能够在不同的函数中重用异常处理(
_onPress
和 onPress1
)。但是 then
总是被执行。
I/flutter (15240): Test
I/flutter (15240): Timeout reaching the server
I/flutter (15240): Do something after fetch
我希望仅在未捕获到异常时才执行最后一次打印。