StreamProvider not updating state

会有一股神秘感。 提交于 2020-01-14 15:48:32

问题


I am trying to use a StreamProvider (from this awesome package), but I've been struggling to get a particular stream to work.

I create a StreamController which I use to add data to its Stream via its Sink. All of this seems to be working fine. But when using this Stream with a StreamProvider, the widget tree does not reflect the changes of the Stream. It does however work fine using a StreamBuilder.

The code using a StreamProvider:

class TestPage extends StatelessWidget {
  final Mockup exchange = ExchangeApi.mockup;

  @override
  Widget build(BuildContext context) {
    return StreamProvider<List<Data>>(
      builder: (BuildContext context) => Wrapper.mockup.stream,
      initialData: null,
      catchError: (BuildContext context, e) {
        print("Error: $e");
        return null;
      },
      child: TestPageBody(),
    );
  }
}

class TestPageBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    List<Data> dataList = Provider.of<List<Data>>(context);
    return ListView.builder(
      itemCount: dataList?.length ?? 0,
      itemBuilder: (BuildContext context, int index) {
        return Text(dataList[index].name);
      },
    );
  }
}

I have been searching why this does not work, but haven't found an answer yet. But here are some things I did find:

  • Using Flutter Desktop Embedding, the UI did reflect changes from the stream when the window got resized (thus forcing to rebuild). The same effect is seen when using hot refresh.
  • The stream is constantly adding new data, I tested this by debugging and simply printing out the data

Any help would be greatly appreciated!


回答1:


The default behavior of most providers (excluding ChangeNotifierProvider) is to assume that the values passed are immutable.

As such, if your stream emits the same value as previously emitted, this won't rebuild dependents.

There are two solutions:

  • Make the values emitted by your stream immutable, such that performing previousValue == newValue works correctly.

  • override updateShouldNotify to not filter values if they didn't change.

    A simple updateShouldNotify: (_, __) => true will do.


In the ideal world, prefer immutability.

This can be done by making a copy of your object before sending it to streamController.add(value):

List<T> value;
streamController.add(List.from(value));

A second (optional) step is to override updateShouldNotify (or operator== on your object) to notify the provider that the value didn't change.

With List, this can be done using ListEquality from collection/collection.dart:

import 'package:provider/provider.dart';
import 'package:collection/collection.dart';

StreamProvider<List<int>>(
  builder: (_) => stream,
  updateShouldNotify: const ListEquality<int>().equals,
);


来源:https://stackoverflow.com/questions/57365207/streamprovider-not-updating-state

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!