1

在我的应用程序中,我使用riverpodflutter_tts包来朗读http 响应。首先,我在 FutureProvider 中获取数据后添加它,如下所示:

final futureProvider = FutureProvider.family<String, String>((ref, itemId) async {
  // fetch data from server
  final result = await Future.delayed(Duration(seconds: 1)).then((value) => "$itemId");
  await SpeakResult(result); // speak here
  return result;
});

但即使使用相同的 itemId 多次调用 FutureProvider,它也只是第一次被大声朗读。

其次,我在build方法中添加了它,但是在重建小部件时它总是被大声朗读。

useProvider(futureProvider("item id")).when(
  loading: () => CircularProgressIndicator(),
  error: (error, stackTrace) => Text("$error"),
  data: (value) async {
    await SpeakResult(value);
    return Text("$value");
  },
);

有什么想法可以解决这个问题吗?

完整代码在这里:


final futureProvider = FutureProvider.autoDispose.family<String, String>((ref, id) async {
  ref.onDispose(() => print("disposed"));
  // fetch data from server
  final result = Future.delayed(Duration(seconds: 1)).then((value) => "$id");
  // await SpeakResult(result);
  return result;
});

final asyncListProvider = StateNotifierProvider((_) => AsyncList());

class AsyncList extends StateNotifier<List<AutoDisposeFutureProvider<String>>> {
  AsyncList() : super([]);

  void add(String id) {
    /*
      //I want to do something like this:
      final asyncValue = futureProvider(id).whenData((value) async {
        await SpeakResult(result);
        return value;
      });
    */
    final asyncValue = futureProvider(id);
    state = [asyncValue, ...state];
  }
}

class MyHomePage extends HookWidget {
  const MyHomePage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final list = useProvider(asyncListProvider.state);
    return ListView(
      children: [
        RaisedButton(
          child: Text("Add data"),
          onPressed: () {
            context.read(asyncListProvider).add("item id");
          },
        ),
        for (final item in list)
          useProvider(item).when(
            loading: () => ListTile(
              title: Center(child: CircularProgressIndicator()),
            ),
            error: (error, stackTrace) => Text("$error"),
            data: (value) {
              // await SpeakResult(value);
              return Text("$value");
            },
          ),
      ],
    );
  }
}
4

1 回答 1

0

使用提供者的好处之一是它们是高效的,因为它们只计算一次值,除非发生改变会改变该值。

您在第一个示例中看到该行为的原因:

但即使使用相同的 itemId 多次调用 FutureProvider,它也只是第一次被大声朗读。

是因为我上面提到的提供者的财产。如果您将autoDispose 装饰器添加到您的 futureProvider 我相信这将解决您的问题。

此外,在第二个示例中始终大声朗读它的原因是,即使在视觉上不明显,当发生任何变化时,构建方法中的所有内容都会重新构建。这可以追溯到我关于提供者高效的第一点,因为除非您明确想要这种行为,否则您不必重新评估提供的值。

于 2020-09-22T14:22:51.923 回答