用户更改时,StreamProvider侦听用户的消息不会更新

时间:2020-07-16 10:41:30

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

在我的应用中,我收听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,这会弄乱我应用程序中的某些组件。

有更好的解决方法吗?

1 个答案:

答案 0 :(得分:0)

我设法从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来使它变得更好,更轻巧,该Singleton侦听Authentication中的更改,然后在用户登录时获取当前用户。

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;
        });
    });
  }
}