Proper way to Handle Exceptions in Flutter

Today we will see how we can properly handle errors and exceptions in Flutter.

Proper Error Handling in Flutter

Watch Video Tutorial

Proper Error Handling in Flutter

For this example we will be doing a service call and handle exceptions related to that.

We will create a sample service first.

To make service calls, you may need to add the below plugin in the pubspec.yaml file under dependencies.

http: ^0.12.0+4

Call ‘flutter packages get’ to install the plugin or your editor may automatically do it.

We will also need a User model to parse the user data from the service.

class User {
int id;
String name;
String email;

User({this.id, this.name, this.email});

factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'] as int,
name: json['name'] as String,
email: json['email'] as String,
);
}
}static const String url = 'https://jsonplaceholder.typicode.com/users';

static Future<List<User>> getUsers() async {
try {
final response = await http.get(url);
if (200 == response.statusCode) {
List<User> users = parseUsers(response.body);
return users;
} else {
return List<User>();
}
} catch (e) {
throw Exception(e.message);
}
}

static List<User> parseUsers(String responseBody) {
final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<User>((json) => User.fromJson(json)).toList();
}

In the above example we are catching all exceptions using a simple try catch block which is not suitable since there can be a variety of Exceptions in this scenario like a SocketException, HttpException or a FormatException.

So in that case how do we catch those exceptions separately and provide appropriate messages to the user.

Now the beauty of dart is you can throw any custom object as Exception. So let’s create some custom classes to throw for each exception above.

class NoInternetException {
String message;
NoInternetException(this.message);
}

class NoServiceFoundException {
String message;
NoServiceFoundException(this.message);
}

class InvalidFormatException {
String message;
InvalidFormatException(this.message);
}

class UnknownException {
String message;
UnknownException(this.message);
}

Now we will modify our function to get the users above like below

import 'package:http/http.dart' as http;
import 'dart:convert';
import 'User.dart';
import 'Exceptions.dart';

class Services {
static const String url = 'https://jsonplaceholder.typicode.com/users';

static Future<List<User>> getUsers() async {
try {
final response = await http.get(url);
if (200 == response.statusCode) {
List<User> users = parseUsers(response.body);
return users;
//throw Exception('Unknown Error');
} else {
return List<User>();
}
} on SocketException catch (e) {
throw NoInternetException('No Internet');
} on HttpException {
throw NoServiceFoundException('No Service Found');
} on FormatException {
throw InvalidFormatException('Invalid Data Format');
} catch (e) {
throw UnknownException(e.message);
}
}

static List<User> parseUsers(String responseBody) {
final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<User>((json) => User.fromJson(json)).toList();
}
}

In the UI, we will catch the exception like this

list() {
return FutureBuilder(
future: users,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<User> users = snapshot.data;
if (users.isEmpty) {
return showError('No Users');
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: users
.map(
(user) => Padding(
padding: EdgeInsets.all(10.0),
child: Text(
user.name,
style: TextStyle(
fontSize: 20.0,
),
),
),
)
.toList(),
);
}
if (snapshot.hasError) {
if (snapshot.error is NoInternetException) {
NoInternetException noInternetException =
snapshot.error as NoInternetException;
return showError(noInternetException.message);
}
if (snapshot.error is NoServiceFoundException) {
NoServiceFoundException noServiceFoundException =
snapshot.error as NoServiceFoundException;
return showError(noServiceFoundException.message);
}
if (snapshot.error is InvalidFormatException) {
InvalidFormatException invalidFormatException =
snapshot.error as InvalidFormatException;
return showError(invalidFormatException.message);
}
UnknownException unknownException =
snapshot.error as UnknownException;
return showError(unknownException.message);
}
return CircularProgressIndicator();
},
);
}

In the above code, we catch each exception accordingly and show the correct error.

And That’s it.

Please leave your valuable comments below this post.

Thanks for reading.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store