Find The Latest Tech Insights, News and Updates to Read

Simplify Your Flutter App with Dependency Injection

Written by Diksha Pathania | Oct 14, 2023 10:53:38 AM
Key Takeaways
  • Learn how to use get_it, a powerful dependency injection package, to manage and inject dependencies in your Flutter app effortlessly.
  • Discover the robust ApiRepository, a vital component for efficient data management and communication with APIs, and see how it simplifies network requests.
  • By leveraging get_it and ApiRepository, you can significantly reduce boilerplate code and focus on what matters most – building exceptional Flutter apps.

Welcome to exciting Flutter journey! As app developers, we're always on the lookout for tools and techniques that make our lives easier and our code more maintainable. One such superhero duo in the Flutter ecosystem is the get_it package and the versatile ApiRepository. 

Dependency Injection in Flutter: Managing Dependencies Like a Pro

In the world of software development, managing dependencies is a critical aspect of building maintainable and scalable applications. Flutter, Google's UI toolkit for building natively compiled applications for mobile, web, and desktop from a single codebase, is no exception. One powerful technique for managing dependencies in Flutter is Dependency Injection (DI). In this blog, we'll delve into what Dependency Injection is, why it's important, and how to implement it in your Flutter projects with some practical code snippets.

What is Dependency Injection?

Dependency Injection is a design pattern that aims to reduce the coupling between components by ensuring that the dependencies of a class are provided from outside the class, rather than being created within the class itself. This approach promotes modularity, testability, and easier maintenance. In simpler terms, it's a way of passing required objects (dependencies) to a class from its outside environment rather than having the class create those dependencies on its own.

Why Use Dependency Injection?

  • Decoupling: Dependency Injection helps in decoupling components, making your codebase more modular and flexible. Changes in one component won't necessarily affect others.
  • Testability: By injecting dependencies, you can easily mock or substitute those dependencies with test doubles during unit testing, making your tests more isolated and reliable.
  • Reusability: Injected dependencies can be reused in multiple places, reducing code duplication and promoting a consistent approach to handling dependencies.
  • Flexibility: Swapping out implementations of a dependency becomes easier. This is especially useful when dealing with different data sources, API clients, or third-party libraries.

Implementing Dependency Injection in Flutter

In Flutter, you can implement Dependency Injection using various libraries and approaches, but we'll focus on one popular package called get_it. This package provides a simple and powerful way to manage dependencies using a Service Locator pattern.

Before starting, let’s see what’s get_it package?

The get_it package is used to register and retrieve instances of classes throughout your Flutter app. It provides a simple service locator mechanism that allows you to define and manage singletons, services, or other objects that need to be accessed from different parts of your application.

Here's a basic overview of how you might use the get_it package in a Flutter app:

  • Add the get_it package to your pubspec.yaml file:

dependencies:

  get_it:  # Use the latest version available

  • Import the package in your Dart code:

import 'package:get_it/get_it.dart';

  • Create an instance of GetIt to manage your dependencies:

GetIt locator = GetIt.instance;

  • Register your dependencies using registerSingleton, registerFactory, or other registration methods:

// Register a singleton instance 

You have to pass an instance of T or a derived class of T that you will always get returned on a call to get<T>(). The newly registered instance is also returned which can be sometimes convenient.

locator.registerSingleton<MyService>(MyService()); 

As creating this instance can be time-consuming at app start-up you can shift the creation to the time the object is the first time requested with:

You have to pass a factory function func that returns an instance of an implementation of T. Only the first time you call get<T>() this factory function will be called to create a new instance. After that, you will always get the same instance returned.

locator.registerLazySingleton(() => AnotherService());

// Register a factory (creates a new instance each time)

You have to pass a factory function func that returns a NEW instance of an implementation of T. Each time you call get<T>() you will get a new instance returned. How to pass parameters to a factory, you can find locator.registerFactory<AnotherService>(() => AnotherService());

  •   Retrieve instances from your GetIt container

MyService myService = locator<MyService>(); 

AnotherService anotherService = locator<AnotherService>();

This allows you to decouple your classes and make your code more testable and modular. Instead of directly creating instances of classes, you retrieve them from the GetIt container, which provides a central point for managing your application's dependencies.

Now let’s use the get_it package to perform Dependency Injection in our code.
In my case, I’m using it for Api Repository.

What is an ApiRepository?

An ApiRepository is a concept commonly used in Flutter apps to handle network requests and interactions with APIs. It abstracts the data fetching logic, making it easier to manage API calls, handle responses, and ensure the separation of concerns in your application.

  • In your main application file, initialize get_it and register your ApiRepository:

import 'package:flutter/material.dart';

import 'package:get_it/get_it.dart';

import 'package:your_app/api_repository.dart';

void main() {

  GetIt.instance.registerLazySingleton(() => ApiRepository());

  

  runApp(MyApp());

}

  • Creating the ApiRepository

class ApiRepository {

  Future<dynamic> fetchData() async {

    // Implement your API call logic here

    // Return the fetched data

  }

}

  • Consuming the Dependency, Now you can consume the ApiRepository dependency from your widgets:

class HomeScreen extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

    final apiRepository = GetIt.instance<ApiRepository>();

 return Scaffold(

    appBar: AppBar(

       title: Text('API Data Fetching'),

      ),

      body: Center(

        child: ElevatedButton(

          onPressed: () async {

            final data = await apiRepository.fetchData();

            // Process and display the data

          },

          child: Text('Fetch Data'),

        ),

      ),

    );

 }

}

Conclusion

In this blog post, we learned how to integrate the get_it package with an ApiRepository in a Flutter application. By using dependency injection, we improved code organization and separation of concerns, making our app more maintainable and testable. The get_it package simplifies the process of managing dependencies and encourages a modular architecture.

Remember that this is just a simple example. In real-world scenarios, your ApiRepository would handle actual API requests and responses. With the power of get_it, you can easily manage complex dependency graphs and keep your codebase clean and efficient.

For more details, please visit https://pub.dev/packages/get_it .

Thank you for joining us on this journey into the world of Flutter, dependency injection, and the magic of ApiRepository. Are you looking for professional help for your Flutter app? Hire Flutter Developers from Your Team in India to help you streamline your app's architecture and make your development process smoother and more efficient.