Flutter BLoC RepositoryProvider is needed when you network call or api request inside from a controller. That means if you have a controller, you should assign it inside RepositoryProvider, then the class would get loaded first.
This controller class would hold methods and fields, that’s necessary when you trigger events and load data or pass data to data layer.
RepositoryProvider should be at the top of your dependency injection, I mean you should inject RepositoryProvider first, so that it’s available to child.
RepositoryProvider takes create and child property to further deal with injection.
RepositoryProvider(
create: ......,
child: BlocProvider(
create: (context) => ......
)
)
The create property refers to a dart class ( a controller), which has methods for network request.
As a child we are using BlocProvider to do dependency injection one more time, this time we are creating BLoCs.
Inside RepositoryProvider we load a dart class, that class instance we pass inside BlocProvider.
So a build() method may look like this.
Widget build(BuildContext context) {
return RepositoryProvider(
create: (context) => AuthRepository(),
child: BlocProvider(
create: (context) => AuthBloc(
authRepository: RepositoryProvider.of<AuthRepository>(context),
),
child: MaterialApp(
home: ........,
),
),
);
}
Here we created an AuthBloc(it’s just a bloc), you may create any kind of BLoCs. Inside AuthBloc we are passing an AuthRepository() using RepositoryProvider.of<AuthRepository>(context).
Let’s look at our AuthRepository. It’s just a controller with bunch of methods. Our AuthBloc needs to access the methods, so we need to pass the AuthRepository instance to our AuthBloc class. At first glance, AuthRepository looks like this.
class AuthRepository{
final _firebaseAuth = FirebaseAuth.instance;
}
Above we see a class. This class is our class. It may hold anything like fields and methods. Those methods we need to access in our Bloc class.
One of the methods could be
Future<void> signUp({required String email, required String password}) async {
try {
await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password);
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
throw Exception('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
throw Exception('The account already exists for that email.');
}
} catch (e) {
throw Exception(e.toString());
}
}
Summary
RepositoryProvider acts like Repository pattern
It’s Data Provider provide data to Bloc, so Bloc do not need to know data come from cloud or sqflite
Hi, is AuthRepository the abstract interface or the concrete implementation of the repository? According to my limited knowledge, I should be coding to the interface, but I have examples using the repo implementation and I cannot find out why this is a good or bad idea. I think it’s bad because with Impl i have a tight coupling between main.dart and RepoImpl, but perhaps they are injecting the Impl for a good reason, do you know what that reason might be?
Thanks
Dave
AuthRepository() just contains abstract class with methods name. AuthRepoImpl should implement the methods. Well, this is clean architecture approach, definitely this better.