简体   繁体   English

Flutter:尝试将 BlocProvider 与 get_it 和 auto_route package 结合使用,但上下文找不到提供程序

[英]Flutter: Try to use BlocProvider with get_it and auto_route package but context don't find provider

I try to make a login page for my app who permit to access when password and username are okay.我尝试为我的应用程序制作一个登录页面,当密码和用户名正确时允许访问。

I have some problem with my bloc provider.我的 bloc 提供商有问题。 My application uses the auto_route package for routing, get_it for dependency injection and block to handle business logic/status.我的应用程序使用 auto_route package 进行路由,使用 get_it 进行依赖注入,并使用块来处理业务逻辑/状态。

The flow is as follows: I initialize the dependencies of my get_it instance in an asynchronous init() function. In these dependencies is among others my AppRouter.流程如下:我在异步 init() function 中初始化我的 get_it 实例的依赖项。在这些依赖项中有我的 AppRouter。

Once this is done, I runApp() my MyApp Widget which returns a MaterialApp.router() in which I delegate the routing to my AppRouter.完成后,我运行 App() 我的 MyApp Widget,它返回一个 MaterialApp.router(),我在其中将路由委托给我的 AppRouter。 The router is configured to have my LoginScreen as the initial page.路由器配置为将我的 LoginScreen 作为初始页面。

My Login page is a Scaffold for a child BlocProvider.我的登录页面是子 BlocProvider 的脚手架。 This BlocProvider creates the bloc thanks to my locator service (get_it) and takes as child my body() widget.由于我的定位器服务 (get_it),这个 BlocProvider 创建了 bloc,并将我的 body() 小部件作为孩子。

In body() I have a button that takes an onPressed function as parameter.在 body() 我有一个按钮,它接受一个 onPressed function 作为参数。 I give it my tryToLogin function as parameter, use the context to find my bloc and send the LoginWithPasswordAndUsername event.我给它我的 tryToLogin function 作为参数,使用上下文找到我的集团并发送 LoginWithPasswordAndUsername 事件。

It's this last step that is stuck: when I click on my button, Flutter tells me that it can't find my Provider in the BuildContext.这是卡住的最后一步:当我单击我的按钮时,Flutter 告诉我它无法在 BuildContext 中找到我的提供者。 I don't understand where this can come from, is it my router that is at fault?我不明白这是从哪里来的,是我的路由器有问题吗? or another element that I didn't see?还是我没看到的其他元素? The logic seems good to me and I really can't find it.逻辑对我来说似乎很好,我真的找不到它。 Could you please help me?请你帮助我好吗?

You can find the code below.您可以在下面找到代码。

main.dart主要.dart

import 'package:flutter/material.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:lansknet/presentation/pages/Login.dart';
import 'package:lansknet/router/router.dart';
import 'package:lansknet/injection_container.dart' as di;

void main() async {
  WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
  FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
  await di.init().then((_) => FlutterNativeSplash.remove());
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  MyApp({
    Key? key,
  }) : super(key: key);

  final _appRouter = di.getIt<AppRouter>();

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerDelegate: _appRouter.delegate(),
      routeInformationParser: _appRouter.defaultRouteParser(),
      title: "Lansknet",
      debugShowCheckedModeBanner: false,
      theme: ThemeData(),
      darkTheme: ThemeData.dark(),
    );
  }
}

injection_container.dart injection_container.dart

import 'package:get_it/get_it.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
import 'package:lansknet/core/network_info.dart';
import 'package:lansknet/data/datasources/auth_local_data_source.dart';
import 'package:lansknet/data/datasources/auth_remote_data_source.dart';
import 'package:lansknet/data/repositories/auth_repository_impl.dart';
import 'package:lansknet/domain/repositories/AuthRepository.dart';
import 'package:lansknet/domain/usecases/Login.dart';
import 'package:lansknet/presentation/blocs/bloc/auth_bloc.dart';
import 'package:lansknet/presentation/utils/input_converter.dart';
import 'package:lansknet/router/router.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http;

final getIt = GetIt.instance;

Future<void> init() async {
  //! Features - Auth
  // Bloc
  getIt.registerFactory(
    () => AuthBloc(login: getIt()),
  );

  // Use cases
  getIt.registerLazySingleton(() => Login(getIt()));

  // Repository
  getIt.registerLazySingleton<AuthRepository>(
    () => AuthRepositoryImpl(
      localDataSource: getIt(),
      networkInfo: getIt(),
      remoteDataSource: getIt(),
    ),
  );

  // Data sources
  getIt.registerLazySingleton<AuthRemoteDataSource>(
    () => AuthRemoteDataSourceImpl(client: getIt()),
  );

  getIt.registerLazySingleton<AuthLocalDataSource>(
    () => AuthLocalDataSourceImpl(sharedPreferences: getIt()),
  );

  //! Core
  getIt.registerLazySingleton(() => InputConverter());
  getIt.registerLazySingleton<NetworkInfo>(() => NetworkInfoImpl(getIt()));

  //! External
  final sharedPreferences = await SharedPreferences.getInstance();
  getIt.registerLazySingleton(() => sharedPreferences);
  getIt.registerLazySingleton(() => http.Client());
  getIt.registerLazySingleton(() => InternetConnectionChecker());

  //! Routes
  getIt.registerSingleton<AppRouter>(AppRouter());
}

router.dart路由器.dart

import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:lansknet/presentation/pages/home.dart';
import 'package:lansknet/presentation/pages/login.dart';
part 'router.gr.dart';

@MaterialAutoRouter(replaceInRouteName: 'Screen,Route', routes: <AutoRoute>[
  AutoRoute(page: LoginScreen, initial: true, path: '/login'),
  AutoRoute(page: HomeScreen, path: '/home')
])
class AppRouter extends _$AppRouter {}

router.gr.dart router.gr.dart

// **************************************************************************
// AutoRouteGenerator
// **************************************************************************

// GENERATED CODE - DO NOT MODIFY BY HAND

// **************************************************************************
// AutoRouteGenerator
// **************************************************************************
//
// ignore_for_file: type=lint

part of 'router.dart';

class _$AppRouter extends RootStackRouter {
  _$AppRouter([GlobalKey<NavigatorState>? navigatorKey]) : super(navigatorKey);

  @override
  final Map<String, PageFactory> pagesMap = {
    LoginRoute.name: (routeData) {
      return MaterialPageX<dynamic>(routeData: routeData, child: LoginScreen());
    },
    HomeRoute.name: (routeData) {
      return MaterialPageX<dynamic>(
          routeData: routeData, child: const HomeScreen());
    }
  };

  @override
  List<RouteConfig> get routes => [
        RouteConfig('/#redirect',
            path: '/', redirectTo: '/login', fullMatch: true),
        RouteConfig(LoginRoute.name, path: '/login'),
        RouteConfig(HomeRoute.name, path: '/home')
      ];
}

/// generated route for
/// [LoginScreen]
class LoginRoute extends PageRouteInfo<void> {
  const LoginRoute() : super(LoginRoute.name, path: '/login');

  static const String name = 'LoginRoute';
}

/// generated route for
/// [HomeScreen]
class HomeRoute extends PageRouteInfo<void> {
  const HomeRoute() : super(HomeRoute.name, path: '/home');

  static const String name = 'HomeRoute';
}

login.dart problem function is on the low of this login.dart问题 function 就在这个低端

import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lansknet/injection_container.dart';
import 'package:lansknet/presentation/blocs/bloc/auth_bloc.dart';
import 'package:lansknet/presentation/widgets/call_to_action_button.dart';
import 'package:lansknet/presentation/widgets/large_button.dart';
import 'package:lansknet/presentation/widgets/loading_circle.dart';
import 'package:lansknet/presentation/widgets/login_field.dart';
import 'package:lansknet/presentation/widgets/login_input_text_field.dart';
import 'package:lansknet/router/router.dart';
import 'package:provider/provider.dart';
import 'package:lansknet/injection_container.dart';

class LoginScreen extends StatefulWidget {
  @override
  _LoginScreenState createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final TextEditingController emailField = TextEditingController();
  final TextEditingController passwordField = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocProvider(
        create: (context) => getIt<AuthBloc>(),
        child: body(context),
      ),
    );
  }

  Widget body(BuildContext context) {
    return AnnotatedRegion<SystemUiOverlayStyle>(
      value: SystemUiOverlayStyle.light,
      child: GestureDetector(
        child: Stack(
          children: <Widget>[
            Container(
                height: double.infinity,
                width: double.infinity,
                decoration: const BoxDecoration(
                  gradient: LinearGradient(
                      begin: Alignment.topCenter,
                      end: Alignment.bottomCenter,
                      colors: [
                        Color.fromRGBO(0, 255, 255, 1),
                        Color.fromRGBO(0, 200, 205, 1),
                        Color.fromRGBO(0, 150, 155, 1),
                        Color.fromRGBO(0, 120, 125, 1),
                      ]),
                ),
                child: SingleChildScrollView(
                  physics: const AlwaysScrollableScrollPhysics(),
                  padding:
                      const EdgeInsets.symmetric(horizontal: 25, vertical: 120),
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      const Align(
                        alignment: Alignment.topLeft,
                        child: Text(
                          "Sign In",
                          style: TextStyle(
                              color: Colors.white,
                              fontSize: 40,
                              fontWeight: FontWeight.bold),
                        ),
                      ),
                      const SizedBox(height: 50),
                      LoginField(
                          emailField: emailField, passwordField: passwordField),
                      const CallToActionButton(text: 'Forgot password'),
                      //buildRemeberCb(),
                      LargeButton(
                          name: "Login",
                          onPressed: () =>
                              {tryToLogin(emailField, passwordField)},
                          color: const Color.fromRGBO(0, 200, 205, 1)),
                      BlocBuilder<AuthBloc, AuthState>(
                          builder: (context, state) {
                        if (state is Loading) {
                          return const LoadingCircle();
                        } else if (state is Loaded) {
                          AutoRouter.of(context)
                              .replaceAll([const HomeRoute()]);
                        } else if (state is Error) {
                          return SnackBar(
                            backgroundColor: Colors.redAccent,
                            content: Text(state.message),
                          );
                        }
                        return Container();
                      })
                    ],
                  ),
                ))
          ],
        ),
      ),
    );
  }

  void tryToLogin(TextEditingController email, TextEditingController password) {
    context
        .read<AuthBloc>()
        .add(LoginWithPasswordAndUsername(email.text, password.text));
  }
}

Output Output

══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
The following ProviderNotFoundException was thrown while handling a gesture:
Error: Could not find the correct Provider<AuthBloc> above this LoginScreen Widget

This happens because you used a `BuildContext` that does not include the provider
of your choice. There are a few common scenarios:

- You added a new provider in your `main.dart` and performed a hot-reload.
  To fix, perform a hot-restart.

- The provider you are trying to read is in a different route.

  Providers are "scoped". So if you insert of provider inside a route, then
  other routes will not be able to access that provider.

- You used a `BuildContext` that is an ancestor of the provider you are trying to read.

  Make sure that LoginScreen is under your MultiProvider/Provider<AuthBloc>.
  This usually happens when you are creating a provider and trying to read it immediately.

  For example, instead of:

  Widget build(BuildContext context) {
    return Provider<Example>(
      create: (_) => Example(),
      // Will throw a ProviderNotFoundError, because `context` is associated
      // to the widget that is the parent of `Provider<Example>`
      child: Text(context.watch<Example>()),
    ),
  }

  consider using `builder` like so:

  Widget build(BuildContext context) {
    return Provider<Example>(
      create: (_) => Example(),
      // we use `builder` to obtain a new `BuildContext` that has access to the provider
      builder: (context) {
        // No longer throws
        return Text(context.watch<Example>()),
      }
    ),
  }

If none of these solutions work, consider asking for help on StackOverflow:
https://stackoverflow.com/questions/tagged/flutter

When the exception was thrown, this was the stack:
#0      Provider._inheritedElementOf (package:provider/src/provider.dart:356:7)
#1      Provider.of (package:provider/src/provider.dart:293:30)
#2      ReadContext.read (package:provider/src/provider.dart:656:21)
#3      _LoginScreenState.tryToLogin (package:lansknet/presentation/pages/login.dart:109:10)
#4      _LoginScreenState.body.<anonymous closure> (package:lansknet/presentation/pages/login.dart:81:32)
#5      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:1005:21)
#6      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:198:24)
#7      TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:613:11)
#8      BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:298:5)
#9      BaseTapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:269:7)
#10     GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:157:27)
#11     GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:449:20)
#12     GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:425:22)
#13     RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:329:11)
#14     GestureBinding._handlePointerEventImmediately (package:flutter/src/gestures/binding.dart:380:7)
#15     GestureBinding.handlePointerEvent (package:flutter/src/gestures/binding.dart:344:5)
#16     GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:302:7)
#17     GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:285:7)
#21     _invoke1 (dart:ui/hooks.dart:170:10)
#22     PlatformDispatcher._dispatchPointerDataPacket (dart:ui/platform_dispatcher.dart:331:7)
#23     _dispatchPointerDataPacket (dart:ui/hooks.dart:94:31)
(elided 3 frames from dart:async)

Handler: "onTap"
Recognizer:
  TapGestureRecognizer#b548c
════════════════════════════════════════════════════════════════════════════════════════════════════

Maybe you are missing a builder?也许你错过了一个建设者?

Try the code below.试试下面的代码。

 @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocProvider(
        create: (context) => getIt<AuthBloc>(),
        child: Builder(
          builder: (context) => body(context),
        ),
      ),
    );
  }

You provide the bloc, but not the BlocBuilder.您提供 bloc,但不提供 BlocBuilder。 See below (I combined the build and body methods, since build() just called body() ).见下文(我结合了buildbody方法,因为build()刚刚称为body() )。

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocProvider(
        create: (context) => getIt<AuthBloc>(),
        child: BlocBuilder<AuthBloc, AuthState>(
          builder: (context, state) {
    return AnnotatedRegion<SystemUiOverlayStyle>(
      value: SystemUiOverlayStyle.light,
      child: GestureDetector(
        child: Stack(
          children: <Widget>[
            Container(
                height: double.infinity,
                width: double.infinity,
                decoration: const BoxDecoration(
                  gradient: LinearGradient(
                      begin: Alignment.topCenter,
                      end: Alignment.bottomCenter,
                      colors: [
                        Color.fromRGBO(0, 255, 255, 1),
                        Color.fromRGBO(0, 200, 205, 1),
                        Color.fromRGBO(0, 150, 155, 1),
                        Color.fromRGBO(0, 120, 125, 1),
                      ]),
                ),
                child: SingleChildScrollView(
                  physics: const AlwaysScrollableScrollPhysics(),
                  padding:
                      const EdgeInsets.symmetric(horizontal: 25, vertical: 120),
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      const Align(
                        alignment: Alignment.topLeft,
                        child: Text(
                          "Sign In",
                          style: TextStyle(
                              color: Colors.white,
                              fontSize: 40,
                              fontWeight: FontWeight.bold),
                        ),
                      ),
                      const SizedBox(height: 50),
                      LoginField(
                          emailField: emailField, passwordField: passwordField),
                      const CallToActionButton(text: 'Forgot password'),
                      //buildRemeberCb(),
                      LargeButton(
                          name: "Login",
                          onPressed: () =>
                              {tryToLogin(emailField, passwordField)},
                          color: const Color.fromRGBO(0, 200, 205, 1)),
                      BlocBuilder<AuthBloc, AuthState>(
                          builder: (context, state) {
                        if (state is Loading) {
                          return const LoadingCircle();
                        } else if (state is Loaded) {
                          AutoRouter.of(context)
                              .replaceAll([const HomeRoute()]);
                        } else if (state is Error) {
                          return SnackBar(
                            backgroundColor: Colors.redAccent,
                            content: Text(state.message),
                          );
                        }
                        return Container();
                      })
                    ],
                  ),
                ))
          ],
        ),
      ),
    );
  }

Use implements AutoRouteWrapper from Auto Route Package使用自动路由 Package 中的工具 AutoRouteWrapper

class LoginScreen extends StatefulWidget implements AutoRouteWrapper {
@override
_LoginScreenState createState() =>_LoginScreenState();

@override
Widget wrappedRoute(BuildContext context) {          
return BlocProvider(create: (ctx)=> getIt<AuthBloc>(), child: this);          
 }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Flutter 如何使用提供程序与 get_it package - Flutter How to Use Provider with get_it package Flutter 自动路线 | 如何使用 BlocProvider 包装路由? - Flutter auto_route | How do I wrap a route with BlocProvider? 将flutter升级到1.22.0后auto_route包的问题 - problem with auto_route package after upgrading flutter to 1.22.0 使用 Flutter 中的 auto_route package 到同一页面的多个路径 - Having multiple paths to the same page with the auto_route package in Flutter 如何将 get_it 用于 Provider.of<exampleprovider> (语境)?</exampleprovider> - How to use get_it for Provider.of<ExampleProvider>(context)? Flutter cubit blocprovider 找不到正确的提供者 - Flutter cubit blocprovider couldn't find the correct provider flutter web auto_route:维护模式 - flutter web auto_route: Maintenance Mode Flutter - auto_route _CustomNavigatorState 错误 - Flutter - auto_route _CustomNavigatorState error 在 Flutter auto_route package 中,我需要将构建器转换为什么类型? - In Flutter auto_route package, what type do I need to cast the builder as? 如何使用 auto_route package 在 flutter 应用程序中重新启动 TabPage 上的构建方法 - How to restart the build method on TabPage in flutter app with auto_route package
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM