Flutter中切换用户时如何重置StreamProvider?

问题描述 投票:0回答:1

我正在构建一个 Flutter 应用程序,并在 main.dart 文件中使用 StreamProvider 来提供有关登录用户数据的实时更新。

但是,我遇到了一个问题: • 当我注销并使用不同的用户帐户登录时,仍显示旧用户的信息。 • 只有当我完全关闭应用程序并重新打开它时,显示的信息才会正确更新以反映新用户。

我怀疑 Stream 或 currentUser 变量没有正确重置。我尝试了在网上找到的不同解决方案,但似乎没有任何效果。我对 Flutter 和应用程序开发的了解仍在增长,这个问题让我发疯。

相关代码如下: 主要.dart:

class _MyAppState extends State<MyApp> {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        StreamProvider<UserModel?>(
          create: (context) {
            final firebaseUser = FirebaseAuth.instance.currentUser?.uid;
            if (firebaseUser != null) {
              return OurDatabase().getUserStream(firebaseUser);
            }
            return Stream<UserModel?>.value(null);
          },
          initialData: null,
        ),
      ],
      child: MaterialApp(
        navigatorKey: navigatorKey,
        title: 'GreenEyed',
        theme: ThemeData(primaryColor: const Color.fromRGBO(113, 190, 71, 1)),
        routes: {
          '/': (ctx) => AuthRoot(),
          '/auth_screen': (ctx) => AuthScreen(),
          "/instructions_screen": (ctx) => InstructionScreen(),
          '/my_profile_screen': (ctx) => MyProfileScreen(),
          "/purchase_screen": (ctx) => PurchaseScreen(),
          "/chat_screen": (ctx) => ChatScreen()
        },
        debugShowCheckedModeBanner: false,
      ),
    );
  }
}

在另一个屏幕中注销功能:

  Future signOut() async {
    showDialog(
        context: context,
        barrierDismissible: false,
        builder: (context) => const Center(child: CircularProgressIndicator()));
    try {
      // Limpia el estado del usuario

      await FirebaseAuth.instance.signOut();
      // Notificar al UserAuthNotifier que el usuario ha cerrado sesión.
      
    } on FirebaseAuthException catch (e) {
      print(e);
    }
    navigatorKey.currentState!.popUntil((route) => route.isFirst);
  }

我需要的是一种方法来确保当用户注销时,Stream或当前用户信息被正确清除或重置,以便新用户重新登录时正确显示数据。

我非常感谢任何解决此问题的指导或建议。预先感谢!

flutter firebase dart firebase-authentication stream
1个回答
0
投票

问题是您正在基于常量值创建

Stream
,即创建时(第一次需要时)用户的
uid

您真正想要的是观察用户在

FirebaseAuth
中的变化并对此做出反应。 “我们的”数据库似乎为所提供的用户 ID 返回
Stream<UserModel?>

这里棘手的部分可能是,每次用户 ID 更改时,您都想要 switch 到不同的流,但是

create
StreamProvider
方法只允许您在创建时返回一个流。

您可能已经注意到,这里的关键字是 switch

rxdart
中有一个很好的运算符,它允许您构建一个流,该流可以从其他流切换其元素源并处理它们的订阅:
switchMap

这是示例代码。我出于演示目的模拟了一些课程。

飞镖板:

https://dartpad.dev/?id=ab7a9699c18353cc324ff05191aee8e6

代码:

import 'dart:async';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:rxdart/rxdart.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        StreamProvider<User?>(
          create: (context) {
            return FirebaseAuth.instance
                .userChanges()
                .map((user) => user?.uid)
                .switchMap(
                  (userId) => switch (userId) {
                    null => Stream<User?>.value(null),
                    _ => OurDatabase().getUserStream(userId),
                  },
                );
          },
          initialData: null,
        ),
      ],
      child: const MaterialApp(
        debugShowCheckedModeBanner: false,
        home: AuthStateWidget(),
      ),
    );
  }
}

class AuthStateWidget extends StatelessWidget {
  const AuthStateWidget();

  Widget build(BuildContext context) {
    final user = Provider.of<User?>(context);
    return Scaffold(
      body: Center(
          child: switch (user) {
        null => Text('User is signed out.'),
        _ => Text('Hi, ${user.name}'),
      }),
    );
  }
}

class User {
  final String id;
  final String name;

  const User({
    required this.id,
    required this.name,
  });
}

// These classes can be ignored. They are only used to mock the real classes for demo purposes.

class OurDatabase {
  Stream<User?> getUserStream(String? userId) {
    if (userId == null) {
      return Stream<User?>.value(null);
    }

    return Stream.value(
      User(
        id: userId,
        name: 'User $userId',
      ),
    );
  }
}

class FirebaseAuth {
  late final Random _random = Random();
  late final Stream<FirebaseUser?> _userStream =
      Stream.periodic(const Duration(seconds: 2), (count) {
    final isSignedOut = count % 2 == 0;
    if (isSignedOut) {
      return null;
    }

    final userId = _random.nextInt(10000);

    return FirebaseUser(uid: '$userId');
  });

  FirebaseAuth._();

  static final FirebaseAuth instance = FirebaseAuth._();

  Stream<FirebaseUser?> userChanges() => _userStream;
}

class FirebaseUser {
  final String uid;

  const FirebaseUser({
    required this.uid,
  });
}

© www.soinside.com 2019 - 2024. All rights reserved.