无法使用提供程序和FutureBuilder?

时间:2020-09-28 16:06:40

标签: flutter

我尝试执行此操作,但这似乎并不好。 如果删除FutureBuilderCircularProgressIndicator可以。 但是,最好在存储数据时花点时间。 有可能吗?

我的源代码:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:serialtrip/config/theme.dart';
import 'package:serialtrip/pages/home.dart';
import 'package:serialtrip/pages/login.dart';
import 'package:serialtrip/providers/authProvider.dart';

main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(
          create: (_) => AuthProvider(),
        ),
      ],
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Serialtrip',
      debugShowCheckedModeBanner: false,
      theme: defaultTheme,
      home: context.watch<AuthProvider>().loggedInStatus == Status.LoggedIn
          ? Home()
          : FutureBuilder(
              future: context.read<AuthProvider>().autoLogin(),
              builder: (ctx, authResultSnapshot) =>
                  authResultSnapshot.connectionState == ConnectionState.waiting ? CircularProgressIndicator() : Login(),
            ),
    );
  }
}

错误:

The following assertion was thrown building MyApp(dirty, dependencies: [_InheritedProviderScope<AuthProvider>]):
Tried to use `context.read<AuthProvider>` inside either a `build` method or the `update` callback of a provider.

This is unsafe to do so. Instead, consider using `context.watch<AuthProvider>`.
If you used `context.read` voluntarily as a performance optimisation, the solution
is instead to use `context.select`.
'package:provider/src/provider.dart':
Failed assertion: line 584 pos 9: 'debugIsInInheritedProviderCreate ||
            (!debugDoingBuild && !debugIsInInheritedProviderUpdate)'

4 个答案:

答案 0 :(得分:0)

试图在context.read<AuthProvider>中使用build 方法或提供者的update回调

如果您阅读了文档,将会发现它不鼓励您使用context.read在build方法中使用Provider.of<AuthProvider>(context, listen: false).autoLogin();

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Serialtrip',
      debugShowCheckedModeBanner: false,
      theme: defaultTheme,
      home: context.watch<AuthProvider>().loggedInStatus == Status.LoggedIn
          ? Home()
          : FutureBuilder(
              future: Provider.of<AuthProvider>(context, listen: false).autoLogin(),
              builder: (ctx, authResultSnapshot) =>
                  authResultSnapshot.connectionState == ConnectionState.waiting ? CircularProgressIndicator() : Login(),
            ),
    );
  }
}

答案 1 :(得分:0)

我对FutureProvider的最后一次尝试,但不会自动登录:(

main.dart

 Message.....Failure on QUSPTRUS call.

 Message.....Operation not valid on system domain object.
 Cause..... The requested operation is not valid on a system domain object. The object name is DMCREG in library *CURLIB.
 Recovery.....You should use application programming interfaces to access system domain objects. An alternative is to create the object into the user domain. The QALWUSRDMN system value controls which libraries may contain user domain.objects.

Message.....Failure to obtain a key value for key CMN_JOBD.Failure code = 2. Please contact technical support for assistance.
 
Message..... Failure to initialize TCP Listener.TCP Listener encountered an error during initialization and can not continue execution. Please see previous message for more information about the error.

CDC Engine v.11.4.0
OS IBM i V7R3
Installer account : QSECOFR

authProvider.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:serialtrip/config/theme.dart';
import 'package:serialtrip/pages/home.dart';
import 'package:serialtrip/pages/login.dart';
import 'package:serialtrip/pages/splash.dart';
import 'package:serialtrip/providers/authProvider.dart';

main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(
          create: (_) => AuthProvider(),
        ),
      ],
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Serialtrip',
        debugShowCheckedModeBanner: false,
        theme: defaultTheme,
        home: FutureProvider(
          create: (_) => AuthProvider().autoLogin(),
          initialData: Status.Authenticating,
          child: _showScreen(context),
        ));
  }
}

Widget _showScreen(BuildContext context) {
  switch (context.watch<AuthProvider>().loggedInStatus) {
    case Status.Authenticating:
      return Splash();
    case Status.LoggedIn:
      return Home();
    default:
      return Login();
  }
}

答案 2 :(得分:0)

第一个可能性

为了发挥autoLogin功能的影响,您需要使用Consumer

Widget _showScreen(BuildContext context) {
    return Consumer<Status>(
             builder: (context, loginStatus, child) {
                   switch (loginStatus) {
                      case Status.Authenticating:
                            return Splash();
                      case Status.LoggedIn:
                            return Home();
                      default:
                            return Login();
                               }
                      }

                       );
}
    

如下更新您的autoLogin函数。

Future<Status> autoLogin() async {

    await new Future.delayed(const Duration(seconds: 2));

    _loggedInStatus = Status.LoggedIn;
 
    return _loggedInStatus;
  }

第二种可能性(推荐)

如果您想连续地监听loggingInState的更改,则需要StreamProvider,因为FutureProvier仅监听一次更改。

在这种情况下,

MyApp Class

class MyApp extends StatelessWidget {
     
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
            title: 'Serialtrip',
            debugShowCheckedModeBanner: false,
            theme: defaultTheme,
            home: StreamProvider(
              create: (_) => AuthProvider().autoLogin(),
              initialData: Status.Authenticating,
              child: _showScreen(context),
            ));
      }
    }

AutoLogin Stream您需要将AutoLogin从将来更改为流式播放

Stream<Status> autoLogin() async* {
    _loggedInStatus = Status.Authenticating;
    yield _loggedInStatus;

    await new Future.delayed(const Duration(seconds: 2));

    _loggedInStatus = Status.LoggedIn;
    yield _loggedInStatus;
  }

Consumer保持不变。

Widget _showScreen(BuildContext context) {
    return Consumer<Status>(
             builder: (context, loginStatus, child) {
                   switch (loginStatus) {
                      case Status.Authenticating:
                            return Splash();
                      case Status.LoggedIn:
                            return Home();
                      default:
                            return Login();
                               }
                      }

                       );
}

答案 3 :(得分:0)

好的,我找到了解决方案。我在应用程序首次启动时使用AuthProvider的构造函数来调用autoLogin()。

main.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:serialtrip/config/theme.dart';
import 'package:serialtrip/pages/home.dart';
import 'package:serialtrip/pages/login.dart';
import 'package:serialtrip/pages/splash.dart';
import 'package:serialtrip/providers/authProvider.dart';

main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(
          create: (_) => AuthProvider(),
        ),
      ],
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Serialtrip',
      debugShowCheckedModeBanner: false,
      theme: defaultTheme,
      home: _showScreen(context),
    );
  }
}

Widget _showScreen(BuildContext context) {
  switch (context.watch<AuthProvider>().loggedInStatus) {
    case Status.Authenticating:
      return Splash();
    case Status.LoggedIn:
      return Home();
    default:
      return Login();
  }
}

authProvider.dart

import 'package:flutter/widgets.dart';

enum Status { NotLoggedIn, Authenticating, LoggedIn }

class AuthProvider with ChangeNotifier {
  Status _loggedInStatus = Status.NotLoggedIn;

  Status get loggedInStatus => _loggedInStatus;

  /// Constructor
  AuthProvider() {
    _autoLogin();
  }

  /// Auto-login
  Future<void> _autoLogin() async {
    _loggedInStatus = Status.Authenticating;
    notifyListeners();
    print('autologin - waiting');

    await new Future.delayed(const Duration(seconds: 5));

    _loggedInStatus = Status.LoggedIn;
    notifyListeners();
    print('autologin - sucess');
  }

  /// Login
  Future<void> login(String email, String password) async {
    _loggedInStatus = Status.Authenticating;
    notifyListeners();
    print('login - waiting');

    await new Future.delayed(const Duration(seconds: 2));

    _loggedInStatus = Status.LoggedIn;
    notifyListeners();
    print('login - sucess');
  }

  /// Logout
  Future<void> logout() async {
    _loggedInStatus = Status.NotLoggedIn;
    notifyListeners();
    print('logout - sucess');
  }
}