After following the first 2 parts, it comes time for the last part. I think I put too much code in 2 previous part and because it still incomplete, we don’t have a chance to run it. Maybe some other time I’ll rewrite it with clearer steps, but for now let’s just finish what we have so far.
Dependency Injection
In clean architecture, we use dependency injection (or DI in short) to make our project cleaner. In a traditional way of creating an instance, we need to use contructor injection as we pass the required parameters to the constructor. It will make a mess if we are creating many instances throughout the project, because it will scattered anywhere.
There are many ways to achieve dependency injection in Flutter, for this project I will use GetIt. Let’s create our injection_container
, this class is responsible for creating all the instances that we need in our project.
// injection_container.dart
import 'package:clean_architecture/core/network/network.dart';
import 'package:clean_architecture/features/weather/data/data_sources/remote/weather_api_remote_data_source.dart';
import 'package:clean_architecture/features/weather/data/repositories/weather_api_repository_impl.dart';
import 'package:clean_architecture/features/weather/domain/repositories/weather_api_repository.dart';
import 'package:clean_architecture/features/weather/domain/use_cases/get_current_weather.dart';
import 'package:clean_architecture/features/weather/presentation/bloc/current_weather_bloc.dart';
import 'package:get_it/get_it.dart';
final getIt = GetIt.instance;
void setup() {
// network
getIt.registerLazySingleton<Network>(() => NetworkImpl());
// data sources
getIt.registerLazySingleton<WeatherApiRemoteDataSource>(
() => WeatherApiRemoteDataSourceImpl(
network: getIt(),
),
);
// repositories
getIt.registerLazySingleton<WeatherApiRepository>(
() => WeatherApiRepositoryImpl(
weatherApiRemoteSource: getIt(),
),
);
// use cases
getIt.registerLazySingleton<GetCurrentWeather>(
() => GetCurrentWeather(
weatherApiRepository: getIt(),
),
);
// blocs
getIt.registerFactory<CurrentWeatherBloc>(
() => CurrentWeatherBloc(
getCurrentWeather: getIt(),
),
);
}
Now we have all the required components for our app, lets look at the main.dart
file.
// lib/main.dart
import 'package:clean_architecture/core/router/app_router.dart';
import 'package:clean_architecture/features/weather/presentation/bloc/current_weather_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'injection_container.dart' as ic;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// dependency injection setup
ic.setup();
await ic.getIt.allReady();
runApp(WeatherApp());
}
class WeatherApp extends StatelessWidget {
WeatherApp({super.key});
final _appRouter = AppRouter();
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<CurrentWeatherBloc>(
create: (context) => ic.getIt(),
),
],
child: MaterialApp.router(
debugShowCheckedModeBanner: false,
title: 'Weather App',
routerConfig: _appRouter.config(),
),
);
}
}
Testing
.