Bird
Raised Fist0
Fluttermobile~20 mins

Loading and error states in Flutter - Mini App: Build & Ship

Choose your learning style10 modes available
Build: Data Fetch Screen
This screen fetches data from a fake source and shows loading and error states.
Target UI
-------------------------
| Data Fetch Screen      |
|-----------------------|
| [Loading spinner]      |
|                       |
|                       |
|                       |
|                       |
|                       |
|                       |
|                       |
|                       |
-------------------------
Show a CircularProgressIndicator while loading data.
Show an error message with a Retry button if loading fails.
Show the fetched data text when loading succeeds.
Retry button triggers data fetch again.
Starter Code
Flutter
import 'package:flutter/material.dart';

class DataFetchScreen extends StatefulWidget {
  @override
  State<DataFetchScreen> createState() => _DataFetchScreenState();
}

class _DataFetchScreenState extends State<DataFetchScreen> {
  bool _isLoading = false;
  bool _hasError = false;
  String _data = '';

  void _fetchData() async {
    // TODO: Implement data fetching with loading and error states
  }

  @override
  void initState() {
    super.initState();
    _fetchData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Data Fetch Screen')),
      body: Center(
        child: // TODO: Show loading spinner, error message with retry, or data text
      ),
    );
  }
}
Task 1
Task 2
Task 3
Task 4
Task 5
Task 6
Solution
Flutter
import 'package:flutter/material.dart';
import 'dart:math';

class DataFetchScreen extends StatefulWidget {
  @override
  State<DataFetchScreen> createState() => _DataFetchScreenState();
}

class _DataFetchScreenState extends State<DataFetchScreen> {
  bool _isLoading = false;
  bool _hasError = false;
  String _data = '';

  Future<void> _fetchData() async {
    setState(() {
      _isLoading = true;
      _hasError = false;
      _data = '';
    });

    await Future.delayed(Duration(seconds: 2));

    bool success = Random().nextBool();

    if (success) {
      setState(() {
        _isLoading = false;
        _data = 'Here is the fetched data!';
      });
    } else {
      setState(() {
        _isLoading = false;
        _hasError = true;
      });
    }
  }

  @override
  void initState() {
    super.initState();
    _fetchData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Data Fetch Screen')),
      body: Center(
        child: _isLoading
            ? CircularProgressIndicator()
            : _hasError
                ? Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Text('Failed to load data.', style: TextStyle(color: Colors.red, fontSize: 16)),
                      SizedBox(height: 12),
                      ElevatedButton(
                        onPressed: _fetchData,
                        child: Text('Retry'),
                      ),
                    ],
                  )
                : Text(_data, style: TextStyle(fontSize: 18)),
      ),
    );
  }
}

This screen uses a StatefulWidget to manage loading, error, and data states.

The _fetchData method simulates a network call with a 2-second delay. It randomly decides success or failure.

While loading, it shows a CircularProgressIndicator. If an error occurs, it shows a red error message and a Retry button. On success, it shows the fetched data text.

The Retry button calls _fetchData again to retry loading.

Final Result
Completed Screen
-------------------------
| Data Fetch Screen      |
|-----------------------|
|       (spinner)        |
|                       |
|                       |
|                       |
|                       |
|                       |
|                       |
|                       |
-------------------------

-- OR --

-------------------------
| Data Fetch Screen      |
|-----------------------|
| Failed to load data.   |
|                       |
|       [Retry]         |
|                       |
|                       |
|                       |
|                       |
|                       |
-------------------------

-- OR --

-------------------------
| Data Fetch Screen      |
|-----------------------|
| Here is the fetched    |
| data!                 |
|                       |
|                       |
|                       |
|                       |
|                       |
|                       |
-------------------------
When the screen opens, a spinner shows for 2 seconds.
After loading, either data text appears or error message with Retry button.
Tapping Retry repeats the loading process.
Stretch Goal
Add a pull-to-refresh gesture to reload the data.
💡 Hint
Wrap the body with a RefreshIndicator widget and call _fetchData on refresh.

Practice

(1/5)
1. What is the main purpose of showing a loading state in a Flutter app?
easy
A. To inform the user that data is being fetched or processed
B. To display an error message when something fails
C. To navigate to a new screen automatically
D. To permanently block user interaction

Solution

  1. Step 1: Understand loading state purpose

    Loading states indicate to users that the app is busy fetching or processing data.
  2. Step 2: Differentiate from error state

    Error states show problems, not progress. Loading states show progress.
  3. Final Answer:

    To inform the user that data is being fetched or processed -> Option A
  4. Quick Check:

    Loading state = show progress [OK]
Hint: Loading means waiting, not error or navigation [OK]
Common Mistakes:
  • Confusing loading with error messages
  • Thinking loading blocks app permanently
  • Assuming loading triggers navigation
2. Which Flutter widget is commonly used to show a loading spinner?
easy
A. Text
B. ListView
C. CircularProgressIndicator
D. Container

Solution

  1. Step 1: Identify loading spinner widget

    CircularProgressIndicator is the built-in widget for showing a spinner in Flutter.
  2. Step 2: Exclude other widgets

    Text shows text, Container is a box, ListView shows lists, none show spinners.
  3. Final Answer:

    CircularProgressIndicator -> Option C
  4. Quick Check:

    Spinner widget = CircularProgressIndicator [OK]
Hint: Spinner = CircularProgressIndicator in Flutter [OK]
Common Mistakes:
  • Using Text widget to show spinner
  • Confusing Container with spinner
  • Trying to use ListView for loading
3. What will the following Flutter code display when isLoading is true?
bool isLoading = true;

Widget build(BuildContext context) {
  if (isLoading) {
    return CircularProgressIndicator();
  } else {
    return Text('Data loaded');
  }
}
medium
A. A text saying 'Data loaded'
B. A runtime error
C. An empty screen
D. A circular loading spinner

Solution

  1. Step 1: Check condition when isLoading is true

    The if condition is true, so CircularProgressIndicator() is returned.
  2. Step 2: Understand widget output

    CircularProgressIndicator shows a spinner, not text or error.
  3. Final Answer:

    A circular loading spinner -> Option D
  4. Quick Check:

    isLoading true shows spinner [OK]
Hint: If isLoading true, show spinner widget [OK]
Common Mistakes:
  • Assuming text shows when loading is true
  • Expecting empty screen instead of spinner
  • Thinking code causes error
4. Identify the error in this Flutter snippet for showing error or loading states:
bool hasError = false;
bool isLoading = true;

Widget build(BuildContext context) {
  if (hasError) {
    return Text('Error occurred');
  } else if (isLoading) {
    CircularProgressIndicator();
  } else {
    return Text('Content loaded');
  }
}
medium
A. Missing return before CircularProgressIndicator()
B. Wrong boolean variable names
C. Text widget cannot show error messages
D. Using else if instead of if

Solution

  1. Step 1: Check all return statements

    hasError branch returns Text, else branch returns Text, but isLoading branch calls CircularProgressIndicator without return.
  2. Step 2: Understand Flutter build method needs return

    Every branch must return a widget; missing return causes error.
  3. Final Answer:

    Missing return before CircularProgressIndicator() -> Option A
  4. Quick Check:

    All branches must return widgets [OK]
Hint: Always return widgets in build method branches [OK]
Common Mistakes:
  • Forgetting return keyword before widgets
  • Confusing variable names
  • Thinking else if is wrong here
5. You want to show a loading spinner, then an error message if loading fails, or content if successful. Which Flutter widget structure correctly handles this with booleans isLoading and hasError?
hard
A. if (isLoading) return CircularProgressIndicator(); else if (hasError) return Text('Error'); else return Text('Content');
B. if (hasError) return Text('Error'); else if (isLoading) return CircularProgressIndicator(); else return Text('Content');
C. if (isLoading && hasError) return CircularProgressIndicator(); else return Text('Content');
D. if (hasError) return CircularProgressIndicator(); else if (isLoading) return Text('Loading'); else return Text('Content');

Solution

  1. Step 1: Prioritize error over loading

    If there is an error, show error message first before loading or content.
  2. Step 2: Show loading only if no error and loading is true

    Then show spinner if loading is true and no error.
  3. Step 3: Show content if no error and not loading

    Finally, show content when no error and loading is false.
  4. Final Answer:

    if (hasError) return Text('Error'); else if (isLoading) return CircularProgressIndicator(); else return Text('Content'); -> Option B
  5. Quick Check:

    Error first, then loading, then content [OK]
Hint: Show error before loading, loading before content [OK]
Common Mistakes:
  • Showing loading before error
  • Combining error and loading in one condition
  • Using wrong widgets for states
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard