In my application, I’m making a network request and trying to handle network errors. I tried:
import 'package:http/http.dart' as http;
// other code omitted
Future<http.Response> postData(String url, Map data) async {
// Setting up body and headers code omitted
final response = await http.post(
Uri.parse(url),
body: body,
headers: headers,
);
return response;
}
void postToServer(BuildContext context) {
// Code to set up data to post omitted
if (data.isNotEmpty) {
try {
postData(url, data).then((http.Response resp) {
var s = resp.statusCode < 400 ? 'succeeded' : 'failed';
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Update $s.')));
}
});
}
catch (e) {
// print(e);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Possible network failure. Try later.')));
}
}
}
The code works fine when the network is available. If I temporarily disable networking, I would have hoped to hit the code in the catch clause when the POST request is made, but that isn’t happening. When debugging in VS Code, ClientException with SocketException exception breakpoints are hit (as expected), but control never passes to the exception handling code … how do I achieve that?
How long are you waiting after disabling the network? You will probably find that the specific behaviour or class of exception varies depending on platform and whether your app has made successful calls within the session. On iOS I think it can be up to 60 seconds before an exception is thrown if connectivity is lost partway through an app session.
How long are you waiting after disabling the network?
Long enough for exceptions to be thrown - in the debugger, exceptions are hit as expected inside framework code, but not propagating to my catch clause. This was observed on an app deployed as a desktop app on Linux … but will eventually plan to deploy it to Android, too. The failure happens during DNS lookup (as expected),.
Don’t mix UI code with infrastructure. It’s a recipe for doom.
Don’t use .then. If something is async, use await. Catch will work.
Try this:
Future<void> postToServer(BuildContext context) async {
// Code to set up data to post omitted
if (data.isNotEmpty) {
try {
final resp = await postData(url, data);
final s = resp.statusCode < 400 ? 'succeeded' : 'failed';
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Update $s.')));
}
}
}
catch (e) {
// print(e);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Possible network failure. Try later.')));
}
}
}
You don’t need to await postToServer. You just need to await where you actually care for the response.
If that does not suit your needs, you can always use .onError along with .then.
A future has 3 completion methods: then, onError and whenComplete. The first is what usually goes between try {}. onError is the catch(ex){}. whenComplete is the finally {}.
Are you referring to the snackbar code in postToServer here? Perhaps postToServer can return e.g. a Future<String> and that then gets displayed in a snackbar by the UI code that calls postToServer from a button press?
Projects are a lot easier if you separate 3 things:
The code that do I/O. This I/O can be databases, GPSs, files, HTTP requests, etc. Those things that are not possible to test in a unit test or that you could change in your project (for instance: Firebase Auth is wonderful for common apps, but it will not work for a corporate/business app (because they need company authentication). Imagine if your whole authentication stack is a plugin, where you can unplug Firebase Authentication and plug in, for example, Zitadel Authentication. NOTHING in your app would change just because you exchange that plugin).
Your domain. The code that asks questions or command your application to do stuff, in a language appropriate for your domain (i.e.: if you are making an Uber application, your domain is those high-level things like drivers, cars, charges, etc. Your app speaks the language of the solution your are building, not databases, apis, etc. that’s tech stuff that nobody (should) care).
Your view (that’s Flutter). It doesn’t make any sense for your views to change because 1) or 2) above changed (of course, unless it’s a feature that requires UI changes).
The more protected those layers are, the less change your app have, the less bugs your app have.
And, if you are into those things, 2) is a wonderful joy to be unit tested.
It’s all about read documentation for Firebase Auth, Zitadel, Drift, Dio, etc. It’s not your problem, you just use those things.
It’s all about your app, so you can test however you want. If you test all cases, logically your app won’t have any bugs
The view is like 1), it’s all about reading Flutter documentation. Since the source of data is 2), you can change your views whatever you like, optimizing a little bit here and there.
Ok. In theory, it’s nice. How about practice?
Run like a vampire runs from garlic from things like BLoC, Riverpod, etc. Those are cancer. It only adds complexity to your project and hinders your ability to be free to do things the way you wanted.
For your business class, what I like to do (and this is only my personal preference) is to use Mediator pattern - Wikipedia. This allows me to write code as questions (what is the current-authenticated user? What is the current list of products available for purchase?) or orders (do authenticate the user using Google Sign In, add this product to the shopping cart). And have those parts communicate with events (a product has being bought, the user X has signed in). For that, I use this: streamline | Flutter package (check the example app and see if that makes sense for you). I like this particular package because it has a feature I’m requiring right now: the ability to ask simultaneously to many parts of my application if they have some event for a specific day in a calendar (it’s like microservices inside your app). And pipelines. Very good for logging performance with Firebase Performance.
It is more work? Yes, it is. It is worth? Yes, hell, it is. It saves A LOT of headache when the app grows. It is worth for simple apps? Yes, because you should do this stuff as a rule. IMO, programming is not writing code, is using a method, a style to solve problems using code. Is the same as a painter style: the final result is a paint, but the way you achieve that is a style on your own. So, you need to practice your style for anything you write, always.
Using contents of this forum for the purposes of training proprietary AI models is forbidden. Only if your AI model is free & open source, go ahead and scrape. Flutter and the related logo are trademarks of Google LLC. We are not endorsed by or affiliated with Google LLC.