Quick, think about this for a second
This lesson steps things up from the first exercise lesson — the tasks require combining Navigator, named routes, FutureBuilder, and the http package all at once. In real app development, passing and returning data as you move between screens, and handling a network call's loading/error state in the UI, both matter a lot. Working through these tasks yourself will help lock in the concepts you saw back in the mini-project lesson. Each task comes with a code skeleton as a sample, but you'll need to fill in the full logic yourself.
Exercises
Task 1: Using named routes ('/', '/detail'), make tapping a ListView item on the Home screen navigate to the Detail screen via Navigator.pushNamed(), passing along the item name as an argument and displaying it on the Detail screen. Task 2: Add a 'Confirm' button on the Detail screen that sends a result back to the Home screen with Navigator.pop(context, true); on the Home screen, receive that result with await Navigator.pushNamed() and show a SnackBar. Task 3: Use the http package to fetch a user list from a public API (e.g. jsonplaceholder.typicode.com/users) with an async function, and use FutureBuilder to show a CircularProgressIndicator while loading, a ListView.builder on success, and an error Text on failure.
Code Example
// Task 1 & 2 skeleton
class DetailScreen extends StatelessWidget {
final String itemName;
const DetailScreen({super.key, required this.itemName});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(itemName)),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context, true);
},
child: const Text('Confirm'),
),
),
);
}
}
// Home screen call
final result = await Navigator.pushNamed(context, '/detail', arguments: 'Item A');
if (result == true) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Confirmed!')),
);
}
// Task 3 skeleton
Future<List<dynamic>> fetchUsers() async {
final res = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/users'));
if (res.statusCode == 200) {
return jsonDecode(res.body);
} else {
throw Exception('Failed to load users');
}
}
// FutureBuilder<List<dynamic>>(
// future: fetchUsers(),
// builder: (context, snapshot) {
// if (snapshot.connectionState == ConnectionState.waiting) {
// return const CircularProgressIndicator();
// } else if (snapshot.hasError) {
// return Text('Error: ${snapshot.error}');
// } else {
// final users = snapshot.data!;
// return ListView.builder(...);
// }
// },
// )Tapping an item on the Home screen takes you to the Detail screen with the argument passed along; pressing Confirm brings up a SnackBar back on Home; and the user list screen goes from a loading indicator to showing the real API data list.5-Minute Challenge
Once you've finished Task 3, add a RefreshIndicator for pull-to-refresh so that swiping down on the screen calls fetchUsers() again (5 minutes).
A Quick Word of Caution
Public APIs often have rate limits, so instead of letting FutureBuilder fire off a new API call on every widget rebuild, store the Future in a state variable during initState() and reuse it from there.