Thuta Learning
ExercisesMobile Developmentbeginner

Exercise: Navigation, Async & API Challenge

Relax. We'll talk through this in plain words — no textbook voice.

What you'll walk away with

  • Work through the Navigation, Async & API Challenge exercise on your own
  • Practice the skills you've already learned until they stick
  • Get comfortable finding bugs, fixing them, and checking your own work

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

dart
// 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(...);
//     }
//   },
// )
You should see
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.

Easy traps

  • Not awaiting pushNamed() and using the result right away, which ends up being null
  • Skipping the snapshot.hasError check in FutureBuilder, assuming data is always there, and using snapshot.data! directly — which crashes the app the moment a network error happens

Try It Yourself Now

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).

You'll know it worked when: 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.

Exercise: Navigation, Async & API Challenge | Thuta Learning