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

Why is RiverPod StreamProvider stuck in loading even though Stream.empty() should be returning when database is null

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

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

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

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 return,则不会调用 data 回调。您很可能只会得到 loading

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