Topic: 6 Understanding Dependency Injection

This is our sixth topic from Learn Flutter: Basic to Advance series

Topic: 6 Understanding Dependency Injection

Hello devs, Today, we'll discuss Dependency Injection. Many tasks that we typically write manually in code can be automated with the help of dependency injection. We simply need to instruct the DI framework about the dependencies we require and how they should be instantiated.

Dependency Injection

Dependency injection is a technique in Flutter where objects or "dependencies" are provided to other objects that need them.

So it's just like you would hand out party hats and balloons to your guests, DI ensures that widgets or classes get the data, services, or other objects they need to work properly.

Alright devs, so the question is why do we use Dependency injection and why not write code manually?

Why use Dependency Injection?

DI makes your code more flexible and modular. Instead of hard-coding dependencies inside widgets or classes, you can inject them from outside. This makes it easier to test, maintain, and change your code later.

It also promotes reusability. You can reuse widgets or classes with different dependencies by injecting them accordingly.

So yeah that's why we use the DI in our App. Okay so now we look out how DI is Work.

How Does Dependency Injection Work in Flutter?

  • In Flutter, you can use packages like get_it, provider, or even built-in Flutter mechanisms like InheritedWidget to perform dependency injection.

  • For example, with get_it, you register dependencies (like a data service or a configuration object) and then retrieve them wherever needed in your app.

  • With provider, you can use Provider.of or Consumer widgets to access dependencies from higher up in the widget tree.

Alright, devs Let's check one example of Dependency injection using getIt and After that the second example of DI using Provider.

Get_It Example

First, add the get_it package to your pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  get_it: ^7.3.1  # Or the latest version available

Then, import the necessary packages and set up the dependency injection:

import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';

// Define a class for the user data
class UserData {
  final String name;
  final int age;

  UserData({required this.name, required this.age});
}

void main() {
  // Initialize GetIt for dependency injection
  GetIt locator = GetIt.instance;

  // Register the UserData class as a dependency
  locator.registerLazySingleton<UserData>(() => UserData(name: 'John Doe', age: 30));

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Dependency Injection Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              // Access user data using GetIt
              Column(
                children: [
                  Text('Name: ${locator<UserData>().name}'),
                  Text('Age: ${locator<UserData>().age}'),
                ],
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: () {
                  // Update user data using GetIt
                  locator<UserData>().name = 'Jane Smith';
                  locator<UserData>().age = 25;
                  // Since UserData is a singleton, changes are reflected everywhere
                },
                child: Text('Update User Data'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

In this example:

  • We import the GetIt package and initialize it as locator.

  • We register UserData as a lazy singleton with locator.registerLazySingleton.

  • Inside the MyApp widget, we access UserData using locator<UserData>() and display its properties in the UI.

  • We also have a button that updates the user data directly through locator<UserData>(), showcasing how changes are reflected globally due to UserData being a singleton.

This example demonstrates how to use get_it for dependency injection in Flutter to manage and access dependencies across your app.

Provider Example

First, make sure to add the provider package to your pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  provider: ^5.0.0  # Or the latest version available

Then, import the necessary packages and set up the dependency injection:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

// Define a class for the user data
class UserData {
  final String name;
  final int age;

  UserData({required this.name, required this.age});
}

// Create a provider for the user data
class UserDataProvider extends ChangeNotifier {
  UserData _userData = UserData(name: 'John Doe', age: 30);

  UserData get userData => _userData;

  void updateUser(UserData newData) {
    _userData = newData;
    notifyListeners(); // Notify listeners when data changes
  }
}

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => UserDataProvider(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Dependency Injection Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              // Access user data using provider
              Consumer<UserDataProvider>(
                builder: (context, userDataProvider, child) {
                  final userData = userDataProvider.userData;
                  return Column(
                    children: [
                      Text('Name: ${userData.name}'),
                      Text('Age: ${userData.age}'),
                    ],
                  );
                },
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: () {
                  // Update user data using provider
                  Provider.of<UserDataProvider>(context, listen: false)
                      .updateUser(UserData(name: 'Jane Smith', age: 25));
                },
                child: Text('Update User Data'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

In this example:

  • We define a UserData class to represent user information.

  • We create a UserDataProvider class that extends ChangeNotifier to manage the user data.

  • We use the provider package to provide the UserDataProvider to the widget tree using ChangeNotifierProvider.

  • Inside the MyApp widget, we use Consumer to access the user data from UserDataProvider and display it in the UI.

  • We also have a button that triggers an update to the user data through the updateUser method in UserDataProvider.

This example demonstrates how to use the provider package for dependency injection in Flutter to manage and update data across your app.

Alright devs, This is the end of our blog i hope this blog helps you to easily understand Dependency Injection. Okay, then We catch up on our next topic async, await, and async*.


Connect with Me:

Hey there! If you enjoyed reading this blog and found it informative, why not connect with me on LinkedIn? 😊 You can also follow my Instagram page for more mobile development-related content. πŸ“²πŸ‘¨β€πŸ’» Let’s stay connected, share knowledge and have some fun in the exciting world of app development! 🌟

Check out my Instagram page

Check out my LinkedIn

Β