简体   繁体   English

如何在 Flutter 中更改 StreamProvider 中的 stream

[英]How to change the stream in StreamProvider in Flutter

I'm consuming a stream from Firebase Firestore with a StreamProvider from the provider -package like the below code snippet shows ( DatabaseService.streamVehicles is just a wrapper function to the actual query to Firestore).我正在使用来自 Firebase Firestore 的 stream 和来自providerStreamProvider - 包,如下面的代码片段所示( DatabaseService.streamVehicles只是 ZC1C425268E68785D1AB5074FC 的包装器)

In response to user events, the locationId variable will be set to different ids to filter in the Firestore query.为响应用户事件, locationId变量将设置为不同的 id 以在 Firestore 查询中进行过滤。 However, whenever locationId changes, the component will rebuild, but the function passed to the create -parameter will not be called again, so the new value of locationId will not be passed to the query and the stream is still the same, unfiltered stream. However, whenever locationId changes, the component will rebuild, but the function passed to the create -parameter will not be called again, so the new value of locationId will not be passed to the query and the stream is still the same, unfiltered stream. How can I make sure a new stream is created whenever locationId changes?如何确保在locationId更改时创建新的 stream?

class HomePage extends StatefulWidget {
  static final String id = 'home';

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final CupertinoTabController _tabController =
      CupertinoTabController(initialIndex: 0);

  String locationId;

  void setLocationId(String newId) {
    this.setState(() {
      locationId = newId;
    });
  }

  @override
  Widget build(BuildContext context) {
    print("Building homepage");
    return Consumer<User>(
      builder: (context, user, _) {
        return StreamProvider<List<Vehicle>>(
          create: (context) => DatabaseService.streamVehicles(
            user.organization.id,
            locationId: locationId,
          ),
          catchError: (ctx, err) {
            print("Error in stream");
            print(err);
            return [];
          },
          child: CupertinoTabScaffold(
            controller: _tabController,
            tabBar: CupertinoTabBar(
              activeColor: kHighlightColor,
              items: <BottomNavigationBarItem>[
                BottomNavigationBarItem(
                  icon: Icon(CupertinoIcons.collections),
                  title: Text('Vehicles'),
                ),
                BottomNavigationBarItem(
                  icon: Icon(CupertinoIcons.settings),
                  title: Text('Settings'),
                ),
              ],
            ),
            tabBuilder: (BuildContext context, int index) {
              switch (index) {
                case 0:
                  return VehiclesPage(
                      locationId: locationId, setLocationId: setLocationId);
                case 1:
                  return SettingsPage();
              }
              return null;
            },
          ),
        );
      },
    );
  }
}

The streamVehicles method of DatabaseService is defined as the following. DatabaseServicestreamVehicles方法定义如下。

  static Stream<List<Vehicle>> streamVehicles(
    String organizationId, {
    String locationId,
  }) {
    final Query ref = _firestore
        .collection('organizations')
        .document(organizationId)
        .collection('vehicles')
        .where(
          "location.id",
          isEqualTo: locationId,
        );

    return ref.snapshots().map((vehicleSnapshots) => vehicleSnapshots.documents
        .map((vehicleSnapshot) => Vehicle.fromFirestore(vehicleSnapshot))
        .toList());
  }

If you want to create a new stream whenever something happens, and then render the contents of that stream, I'd typically store the stream in the state of the widget: If you want to create a new stream whenever something happens, and then render the contents of that stream, I'd typically store the stream in the state of the widget:

void setLocationId(String newId) {
  this.setState(() {
    locationId = newId;
  });
  // TODO: determine the new stream, and set that in the state too
}

Then in your build method, you use the stream from the state, instead of directly from the service.然后在您的build方法中,您使用来自 state 的 stream,而不是直接来自服务。

Use a StreamProvider.family to create a new stream provider unique to each id's.使用 StreamProvider.family 创建一个新的 stream 提供程序,每个 ID 都是唯一的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM