我试图学习如何在flutter项目中设置依赖项注入,但是我遇到了一个问题:
I/flutter (14507): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (14507): The following assertion was thrown building _InheritedProviderScope<NumberTriviaBloc>(value: null):
I/flutter (14507): No type GetConcreteNumberTrivia is registered inside GetIt.
I/flutter (14507): Did you forget to pass an instance name?
I/flutter (14507): (Did you accidentally do GetIt sl=GetIt.instance(); instead of GetIt sl=GetIt.instance;did you
I/flutter (14507): forget to register it?)
I/flutter (14507): 'package:get_it/get_it_impl.dart':
I/flutter (14507): Failed assertion: line 251 pos 14: 'instanceFactory != null'
I/flutter (14507):
I/flutter (14507): The relevant error-causing widget was:
I/flutter (14507): _InheritedProviderScope<NumberTriviaBloc>
依赖初始化:
final sl = GetIt.instance;
void init() {
//! Features - Number Trivia
//* Bloc
sl.registerFactory<NumberTriviaBloc>(() => NumberTriviaBloc(concrete: sl(), inputConverter: sl(), random: sl()));
//* Use cases
sl.registerLazySingleton<UseCase<NumberTrivia, Params>>(() => GetConcreteNumberTrivia(sl()));
sl.registerLazySingleton<UseCase<NumberTrivia, NoParams>>(() => GetRandomNumberTrivia(sl()));
//* Repository
sl.registerLazySingleton<NumberTriviaRepository>(() => NumberTriviaRepositoryImplementation(
localDataSource: sl(), networkInfo: sl(), remoteDataSource: sl()));
//* Data sources
sl.registerLazySingleton<NumberTriviaRemoteDataSource>(
() => NumberTriviaRemoteDataSourceImpl(client: sl()));
sl.registerLazySingleton<NumberTriviaLocalDataSource>(
() => NumberTriviaLocalDataSourceImpl(sharedPreferences: sl()));
//! Core
sl.registerLazySingleton<InputConverter>(() => InputConverter());
sl.registerLazySingleton<NetworkInfo>(() => NetworkInfoImpl(sl()));
//! External
sl.registerLazySingletonAsync<SharedPreferences>(() => SharedPreferences.getInstance());
sl.registerLazySingleton<http.Client>(() => http.Client());
sl.registerLazySingleton<DataConnectionChecker>(() => DataConnectionChecker());
}
我不明白是什么问题,这是其他内容初始化的代码:
class NumberTriviaBloc extends Bloc<NumberTriviaEvent, NumberTriviaState> {
final GetConcreteNumberTrivia getConcreteNumberTrivia;
final GetRandomNumberTrivia getRandomNumberTrivia;
final InputConverter inputConverter;
NumberTriviaBloc(
{@required GetConcreteNumberTrivia concrete,
@required GetRandomNumberTrivia random,
@required this.inputConverter})
: assert(concrete != null),
assert(random != null),
assert(inputConverter != null),
getConcreteNumberTrivia = concrete,
getRandomNumberTrivia = random;
...
}
class GetConcreteNumberTrivia implements UseCase<NumberTrivia, Params>{
final NumberTriviaRepository repository;
GetConcreteNumberTrivia(this.repository);
@override
Future<Either<Failure, NumberTrivia>> call(Params params) async {
return await repository.getConcreteNumberTrivia(params.number);
}
}
class GetRandomNumberTrivia implements UseCase<NumberTrivia, NoParams> {
final NumberTriviaRepository repository;
GetRandomNumberTrivia(this.repository);
@override
Future<Either<Failure, NumberTrivia>> call(NoParams params) async {
return await repository.getRandomNumberTrivia();
}
}
class NumberTriviaRepositoryImplementation implements NumberTriviaRepository {
final NumberTriviaRemoteDataSource remoteDataSource;
final NumberTriviaLocalDataSource localDataSource;
final NetworkInfo networkInfo;
NumberTriviaRepositoryImplementation(
{@required this.remoteDataSource,
@required this.localDataSource,
@required this.networkInfo});
...
}
class NumberTriviaRemoteDataSourceImpl implements NumberTriviaRemoteDataSource {
final http.Client client;
NumberTriviaRemoteDataSourceImpl({@required this.client});
...
}
class NumberTriviaLocalDataSourceImpl implements NumberTriviaLocalDataSource {
final SharedPreferences sharedPreferences;
NumberTriviaLocalDataSourceImpl({@required this.sharedPreferences});
...
}
class InputConverter {}
class NetworkInfoImpl extends NetworkInfo {
final DataConnectionChecker connectionChecker;
NetworkInfoImpl(this.connectionChecker);
...
}
小部件是:
void main() {
di.init();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primaryColor: Colors.green.shade800,
accentColor: Colors.green.shade600,
),
home: NumberTriviaPage(),
);
}
}
class NumberTriviaPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Number Trivia'),
),
body: SingleChildScrollView(child: buildBody(context)),
);
}
BlocProvider<NumberTriviaBloc> buildBody(BuildContext context) {
return BlocProvider<NumberTriviaBloc>(
create: (_) => sl<NumberTriviaBloc>(),
child: Center(
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
children: <Widget>[
SizedBox(
height: 10,
),
BlocBuilder<NumberTriviaBloc, NumberTriviaState>(
// ignore: missing_return
builder: (context, state) {
if (state is Empty) {
return MessageDisplay(
message: 'Start searching',
);
} else if (state is Loading) {
return LoadingWidget();
} else if (state is Loaded) {
return TriviaDisplay(
numberTrivia: state.trivia,
);
} else if (state is Error) {
return MessageDisplay(
message: state.message,
);
}
},
),
SizedBox(
height: 20,
),
TriviaControl()
],
),
),
),
);
}
}
我不知道为什么这对我不起作用。 我遵循了youtube上的教程,并且还在github存储库上检查了该教程中的代码,但这对我没有帮助。 那你能告诉我发生了什么吗?
在tnc1997的帮助下,我收到了一个新错误:
lib/injection_container.dart:27:91: Error: The argument type 'NumberTriviaRepository/*1*/' can't be assigned to the parameter type 'NumberTriviaRepository/*2*/'.
- 'NumberTriviaRepository/*1*/' is from 'package:clean_architecture/features/number_trivia/domain/repositories/number_trivia_repository.dart' ('lib/features/number_trivia/domain/repositories/number_trivia_repository.dart').
- 'NumberTriviaRepository/*2*/' is from 'lib/features/number_trivia/domain/repositories/number_trivia_repository.dart'.
sl.registerLazySingleton<UseCase<NumberTrivia, NoParams>>(() => GetRandomNumberTrivia(sl<NumberTriviaRepository>()));
这是同一文件,下面一行使用相似的合同
//* Use cases
sl.registerLazySingleton<UseCase<NumberTrivia, Params>>(() => GetConcreteNumberTrivia(sl<NumberTriviaRepository>()));
sl.registerLazySingleton<UseCase<NumberTrivia, NoParams>>(() => GetRandomNumberTrivia(sl<NumberTriviaRepository>()));
//* Repository
sl.registerLazySingleton<NumberTriviaRepository>(() => NumberTriviaRepositoryImplementation(
localDataSource: sl<NumberTriviaLocalDataSource>(), networkInfo: sl<NetworkInfo>(), remoteDataSource: sl<NumberTriviaRemoteDataSource>()));
现在我比以前更加困惑
答案 0 :(得分:0)
我非常确定,在使用GetIt
包时,您需要依赖于接口,而不是构造函数中的具体类型。毕竟,依赖项注入的原理之一是依赖于接口而不是实现,因此可以轻松切换实现。我在下面添加了一个代码示例,显示了如何完成此操作。如果您尚未查看文档here,请获取更多信息和代码示例。如果您对代码示例有任何疑问,请随时发表评论!
class NumberTriviaBloc extends Bloc<NumberTriviaEvent, NumberTriviaState> {
final UseCase<NumberTrivia, Params> getConcreteNumberTrivia;
final UseCase<NumberTrivia, NoParams> getRandomNumberTrivia;
final InputConverter inputConverter;
NumberTriviaBloc(
{@required UseCase<NumberTrivia, Params> concrete,
@required UseCase<NumberTrivia, NoParams> random,
@required this.inputConverter})
: assert(concrete != null),
assert(random != null),
assert(inputConverter != null),
getConcreteNumberTrivia = concrete,
getRandomNumberTrivia = random;
...
}
sl.registerFactory<NumberTriviaBloc>(() => NumberTriviaBloc(concrete: sl<UseCase<NumberTrivia, Params>>(), inputConverter: sl<InputConverter>(), random: sl<UseCase<NumberTrivia, NoParams>>()));