Proper way to Handle Exceptions in Flutter

Jamie
3 min readApr 22, 2020

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

Proper Error Handling in Flutter

Watch Video Tutorial

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.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Jamie
Jamie

Written by Jamie

Flutter, React Native, Android, iOS App developer.

No responses yet

Write a response