为什么即使 Stream.empty() 在数据库为 null 时应该返回,RiverPod StreamProvider 仍卡在加载中

问题描述

我正在使用这个 great flutter/riverpod/firebase starter architecture。在导入 top_level_providers.dart 的初始颤动屏幕上,loading 参数是所有调用过的参数。

在我的 accountStreamProvider 中,当 databaseProvider 返回 null 时,发出 Stream.empty(),根据文档“这是一个流,除了在侦听时发送完成事件外,什么都不做。”。>

为什么没有在 data 部分调用 account.when 参数?

root_screen.dart

class AppStartupScreenRouter extends ConsumerWidget {
  const AppStartupScreenRouter({
    Key key,}) : super(key: key);

  @override
  Widget build(BuildContext context,ScopedReader watch) {
    final didCompleteOnboarding = watch(onboardingviewmodelProvider.state);
    AsyncValue<Account> account = watch(accountStreamProvider);

    return account.when(
      data: (data) {
        if (data != null) {
          // evaluate the account info data and
          // return a screen widget
        } else if (didCompleteOnboarding) {
          // return a screen widget
        }

        return IntroScreen();
      },loading: () => LoadingScreen(),error: (err,stack) => EmptyContent(),);
  }
}

top_level_providers.dart

final firebaseAuthProvider =
    Provider<FirebaseAuth>((ref) => FirebaseAuth.instance);

final authStateChangesProvider = StreamProvider<User>(
    (ref) => ref.watch(firebaseAuthProvider).authStateChanges());

final databaseProvider = Provider<FirestoreDatabase>((ref) {
  final auth = ref.watch(authStateChangesProvider);

  if (auth.data?.value?.uid != null) {
    return FirestoreDatabase(uid: auth.data?.value?.uid);
  }

  return null;
});

final accountStreamProvider = StreamProvider<Account>((ref) {
  final db = ref.watch(databaseProvider);
  return db != null ? db.accountStream() : Stream.empty();
});

firestore_database.dart

class FirestoreDatabase {
  FirestoreDatabase({@required this.uid})
      : assert(
            uid != null,'Cannot create FirestoreDatabase entry with null uid');
  final String uid;

  final _service = FirestoreService.instance;

  Future<void> setAccount(Account account) => _service.setData(
        path: FirestorePath.account(uid),data: account.toMap(),);

  Stream<Account> accountStream() => _service.documentStream(
        path: FirestorePath.account(uid),builder: (data,documentId) => Account.fromMap(data,uid),);

  Future<void> deleteAccount(Account account) =>
      _service.deleteData(path: FirestorePath.account(uid));
}

account.dart

@immutable
class Account extends Equatable {
  const Account({
    @required this.id,@required this.firstName,@required this.lastName,});

  final String id;
  final String firstName;
  final String lastName;

  @override
  List<Object> get props => [
        id,firstName,lastName,];

  @override
  bool get stringify => true;

  factory Account.fromMap(Map<String,dynamic> data,String documentId) {
    if (data == null) {
      return null;
    }

    final firstName = data['firstName'] as String;
    final lastName = data['lastName'] as String;

    if (firstName == null || lastName == null) {
      return null;
    }

    return Account(
      id: documentId,firstName: firstName,lastName: lastName,);
  }

  Map<String,dynamic> toMap() {
    return {
      'firstName': firstName,'lastName': lastName,};
  }
}

解决方法

Stream.empty() 从不包含任何数据。如果这是您的 StreamProvider 返回的内容,则不会调用 data 回调。您很可能只会得到 loading

为了获得 data 回调,您的流应至少返回一个元素(无论是否为 null)。