Bird
Raised Fist0
Fluttermobile~20 mins

Service locator pattern in Flutter - Mini App: Build & Ship

Choose your learning style10 modes available
Build: Service Locator Demo
This screen demonstrates how to use the service locator pattern to access a simple greeting service from anywhere in the app.
Target UI
-------------------------
| Service Locator Demo   |
|-----------------------|
| Greeting:             |
|                       |
| [Show Greeting]       |
|                       |
-------------------------
Create a simple GreetingService class with a method that returns a greeting string.
Use a service locator to register and retrieve the GreetingService instance.
Build a screen with a button labeled 'Show Greeting'.
When the button is pressed, display the greeting text below the label 'Greeting:'.
Use the service locator to get the GreetingService inside the widget.
Starter Code
Flutter
import 'package:flutter/material.dart';

// TODO: Create GreetingService class

// TODO: Create ServiceLocator class with register and get methods

void main() {
  // TODO: Register GreetingService instance
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: ServiceLocatorDemo(),
    );
  }
}

class ServiceLocatorDemo extends StatefulWidget {
  const ServiceLocatorDemo({super.key});

  @override
  State<ServiceLocatorDemo> createState() => _ServiceLocatorDemoState();
}

class _ServiceLocatorDemoState extends State<ServiceLocatorDemo> {
  String greeting = '';

  void _showGreeting() {
    // TODO: Use service locator to get GreetingService and update greeting
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Service Locator Demo')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('Greeting:'),
            const SizedBox(height: 8),
            Text(greeting, style: const TextStyle(fontSize: 18)),
            const SizedBox(height: 24),
            ElevatedButton(
              onPressed: _showGreeting,
              child: const Text('Show Greeting'),
            ),
          ],
        ),
      ),
    );
  }
}
Task 1
Task 2
Task 3
Task 4
Solution
Flutter
import 'package:flutter/material.dart';

class GreetingService {
  String getGreeting() => 'Hello from Service Locator!';
}

class ServiceLocator {
  static final Map<Type, Object> _services = {};

  static void register<T>(T service) {
    _services[T] = service!;
  }

  static T get<T>() {
    final service = _services[T];
    if (service == null) {
      throw Exception('Service of type $T not found');
    }
    return service as T;
  }
}

void main() {
  ServiceLocator.register<GreetingService>(GreetingService());
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: ServiceLocatorDemo(),
    );
  }
}

class ServiceLocatorDemo extends StatefulWidget {
  const ServiceLocatorDemo({super.key});

  @override
  State<ServiceLocatorDemo> createState() => _ServiceLocatorDemoState();
}

class _ServiceLocatorDemoState extends State<ServiceLocatorDemo> {
  String greeting = '';

  void _showGreeting() {
    final service = ServiceLocator.get<GreetingService>();
    setState(() {
      greeting = service.getGreeting();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Service Locator Demo')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('Greeting:'),
            const SizedBox(height: 8),
            Text(greeting, style: const TextStyle(fontSize: 18)),
            const SizedBox(height: 24),
            ElevatedButton(
              onPressed: _showGreeting,
              child: const Text('Show Greeting'),
            ),
          ],
        ),
      ),
    );
  }
}

We created a GreetingService class that returns a greeting string. The ServiceLocator class holds a map of services by their type. We register the GreetingService instance in main(). Inside the widget, when the button is pressed, we get the service from the locator and update the UI with the greeting. This pattern lets us access shared services easily from anywhere without passing them around.

Final Result
Completed Screen
-------------------------
| Service Locator Demo   |
|-----------------------|
| Greeting:             |
| Hello from Service    |
| Locator!              |
|                       |
| [Show Greeting]       |
|                       |
-------------------------
User taps 'Show Greeting' button.
Greeting text below 'Greeting:' updates to 'Hello from Service Locator!'.
Stretch Goal
Add a second service called TimeService that returns the current time as a string. Add another button 'Show Time' that displays the current time below the greeting.
💡 Hint
Create TimeService with a method getCurrentTime() returning DateTime.now().toLocal().toString(). Register it in ServiceLocator. Add a new button and use setState to show the time.

Practice

(1/5)
1. What is the main purpose of the Service Locator Pattern in Flutter testing?
easy
A. To handle user input events
B. To create UI widgets dynamically
C. To provide a centralized way to access shared services without passing them manually
D. To manage app navigation routes

Solution

  1. Step 1: Understand the role of service locator

    The service locator pattern provides a central place to get instances of services needed across the app.
  2. Step 2: Compare with other options

    Creating UI widgets, handling input, and managing navigation are unrelated to service locator's purpose.
  3. Final Answer:

    To provide a centralized way to access shared services without passing them manually -> Option C
  4. Quick Check:

    Service locator = centralized service access [OK]
Hint: Service locator centralizes service access, not UI or navigation [OK]
Common Mistakes:
  • Confusing service locator with UI widget creation
  • Thinking it manages navigation or input events
  • Assuming it replaces dependency injection completely
2. Which of the following is the correct way to register a service using the GetIt service locator in Flutter?
easy
A. GetIt.instance.create<MyService>();
B. GetIt.instance.registerSingleton<MyService>(MyService());
C. GetIt.instance.addService(MyService());
D. GetIt.register<MyService>();

Solution

  1. Step 1: Recall GetIt registration syntax

    GetIt uses registerSingleton<T>(instance) to register a singleton service.
  2. Step 2: Check each option

    GetIt.instance.registerSingleton<MyService>(MyService()); matches the correct syntax. Options A, B, and C use invalid or non-existent methods.
  3. Final Answer:

    GetIt.instance.registerSingleton<MyService>(MyService()); -> Option B
  4. Quick Check:

    Register singleton with registerSingleton() [OK]
Hint: Use registerSingleton() to add services in GetIt [OK]
Common Mistakes:
  • Using non-existent methods like addService or create
  • Omitting the instance when registering
  • Confusing registerSingleton with registerFactory
3. Given the following code using GetIt, what will be the output of print(service.getData());?
class MyService {
  String getData() => "Hello from Service";
}

final getIt = GetIt.instance;

void main() {
  getIt.registerSingleton<MyService>(MyService());
  var service = getIt<MyService>();
  print(service.getData());
}
medium
A. Instance of 'MyService'
B. null
C. Error: Service not found
D. Hello from Service

Solution

  1. Step 1: Understand service registration and retrieval

    The service MyService is registered as a singleton and then retrieved correctly.
  2. Step 2: Analyze the method call

    Calling getData() returns the string "Hello from Service" as defined.
  3. Final Answer:

    Hello from Service -> Option D
  4. Quick Check:

    Registered service returns expected string [OK]
Hint: Registered service returns its method output directly [OK]
Common Mistakes:
  • Assuming print shows the instance reference
  • Forgetting to register the service before use
  • Expecting null if service is registered
4. Identify the error in this Flutter test setup using GetIt:
final getIt = GetIt.instance;

void setup() {
  getIt.registerSingleton<MyService>(MyService());
}

void main() {
  setup();
  getIt.registerSingleton<MyService>(MyService());
}
medium
A. Registering the same service twice causes an exception
B. Missing await keyword for async registration
C. Service instance is not created properly
D. GetIt instance is not initialized

Solution

  1. Step 1: Review service registration calls

    The service MyService is registered twice without unregistering first.
  2. Step 2: Understand GetIt behavior on duplicate registration

    GetIt throws an exception if the same service is registered twice without reset or unregister.
  3. Final Answer:

    Registering the same service twice causes an exception -> Option A
  4. Quick Check:

    Duplicate registration = exception [OK]
Hint: Avoid double registering services without unregistering [OK]
Common Mistakes:
  • Assuming async await is needed for registration
  • Thinking service instance creation is faulty
  • Believing GetIt needs explicit initialization
5. You want to write a test in Flutter that uses the service locator pattern to swap a real service with a mock. Which approach correctly achieves this?
hard
A. Unregister the real service, then register the mock service before the test runs
B. Register both real and mock services with the same type simultaneously
C. Create a new instance of the real service inside the test without using the locator
D. Use the real service and ignore mocking for simplicity

Solution

  1. Step 1: Understand service swapping in tests

    To replace a service with a mock, you must unregister the original service first.
  2. Step 2: Register the mock service before test execution

    Registering the mock after unregistering ensures the locator returns the mock during tests.
  3. Final Answer:

    Unregister the real service, then register the mock service before the test runs -> Option A
  4. Quick Check:

    Unregister real, register mock = swap services [OK]
Hint: Unregister real service before registering mock in tests [OK]
Common Mistakes:
  • Registering both real and mock services for same type
  • Not unregistering real service before mock
  • Ignoring service locator and creating instances manually
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