【问题标题】:StreamProvider listening to User doesn't update when User changes当用户更改时,监听用户的 StreamProvider 不会更新
【发布时间】:2020-11-06 00:23:59
【问题描述】:

在我的应用程序中,我聆听来自 Cloud Firestore 中用户文档的更改。 为此,我获取当前用户 ID,然后获取与该 ID 关联的文档。

class UserService {
  ...

  //GET A USER'S INFORMATION AS A STREAM
  // ? IF NO UID IS PASSED, IT GETS THE INFO OF THE CURRENT USER

  Stream<User> getUserInfoAsStream({String uid}) async* {
    if (uid == null) {
      uid = await AuthService().getUID();
    }

    yield* Firestore.instance
        .collection('users')
        .document(uid)
        .snapshots()
        .map((doc) => User.fromFirestore(doc));
  }

  ...

然后我使用StreamProvider 在我的main.dart 中收听流

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        StreamProvider<User>.value(
          value: UserService().getUserInfoAsStream(),
        ),
      ],
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        home: SplashScreen(),
      ),
    ); 
  }
}

在应用程序的生命周期过程中,它可以完美运行,但是当用户使用FirebaseAuth.instance.signOut(); 注销然后使用其他用户登录时,流保持不变(即它会监听旧的 uid 流),并且 StreamProvider 不会监听新的数据流。

| 退出代码供参考 |

// ? SIGN OUT CODE: If user signed out, it returns true, else, false
  Future<bool> signOut() async {
    try {
      await _firebaseAuth.signOut();
      return true;
    } catch (error) {
      print(error);
      return false;
    }
  }

| 在哪里使用 |

FlatButton(
   onPressed: () {
     AuthService().signOut().then((value) =>
       Navigator.of(context).pushAndRemoveUntil(
           CupertinoPageRoute(
              builder: (BuildContext context) {
                   return Onboarding();
             }), (route) => false));
          },
     child: Text("Yes")),

为了解决这个问题,我会将当前的 uid 传递给 StreamProvider,但我只能异步获取当前的 uid。

如何使用 StreamProvider 监听异步流,并在用户更改时更新它?

编辑:我在登录页面后立即将提供程序向上移动到小部件树到屏幕,从而在一定程度上解决了这个问题。但是因为提供程序是有范围的,所以我必须在我原来的 MaterialApp 之后创建一个全新的 MaterialApp,这会弄乱我应用程序中的一些组件。

有没有更好的解决方法?

【问题讨论】:

    标签: firebase flutter dart firebase-authentication flutter-provider


    【解决方案1】:

    我设法通过从provider 包切换到get_it 解决了这个问题。

    get_it 允许您注册和取消注册单例,这意味着当用户登录时,我可以注册单例,以便可以在依赖它的所有屏幕上使用它。然后,当我注销时,我只是取消注册它。这样,用户在登录和退出后总是会更新。

    这里是如何自己做。

    在您的 pubspec.yaml 中安装包 get_it

    get_it: ^4.0.2
    

    在您的 main.dart 旁边创建一个名为 locator.dart 的新文件。在其中添加以下代码:

    GetIt locator = GetIt.instance;
    
    void setupLocator() {
      // Replace this with the object you're trying to listen to.
      User user;
      Stream<User> userStream = UserService().getUserInfoAsStream();
      userStream.listen((event) => user = event);
      locator.registerLazySingleton(() => user); // Register your object
    }
    

    登录时只需拨打setupLocator();,注销时使用此代码:

    locator.unregister<User>();
    

    这就是我为启动和运行它所做的一切!

    编辑:我设法通过使用UserProvider Singleton 使它变得更好更轻,它监听身份验证的变化,然后在用户登录时获取当前用户。

    import 'package:planster/models/core/user.dart';
    import 'package:planster/models/services/auth_service.dart';
    import 'package:planster/models/services/user_service.dart';
    
    class UserProvider {
      // SINGLETON INITIALIZATION
      static final UserProvider _singleton = UserProvider._internal();
    
      factory UserProvider.instance() {
        return _singleton;
      }
      UserProvider._internal() {
        listenToUserAuthState();
      }
    
      // VARIABLES
      User user;
    
      void listenToUserAuthState() async {
        AuthService().onAuthStateChanged.listen((event) {
          uid = event.uid;
          if (uid != null)
            UserService().getUserInfoAsStream(uid: uid).listen((userEvent) {
              user = userEvent;
            });
        });
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-14
      • 2018-06-29
      • 2021-09-27
      • 2016-09-23
      • 1970-01-01
      • 2020-09-08
      • 1970-01-01
      • 2021-03-01
      • 1970-01-01
      相关资源
      最近更新 更多