从未来获取权限流

Get a stream of permissions from a future

我正在尝试流式传输两种类型的基于位置包的数据:

final _location = Location();

runApp(
    MultiProvider(
      providers: [
       StreamProvider<PermissionStatus>(create: (_) => _location.hasPermission().asStream()),
       StreamProvider<bool>(create: (_) => _location.serviceEnabled().asStream()),
      ],
      child: MaterialApp();
    )
)

当我 'stream' 数据时,它加载初始值并流式传输。它不是不断地倾听变化,而这正是我想要做的。我已经尝试将两个期货抽象成它们自己的 class 并创建一个产生当前状态的异步*流,这两个都给出了同样的问题。

我的用例涉及持续监听权限状态和位置 on/off 并在任务之间修改这些部分时关闭 UI 的某些部分。

简化用法:

class LocationWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer2<PermissionStatus, bool>(
        builder: (_, permission, isLocationEnabled, __) => _LocationWidget(
            permission: permission, isLocationEnabled: isLocationEnabled));
  }
}

class _LocationWidget extends StatelessWidget {
  const _LocationWidget({this.permission, this.isLocationEnabled})
      : assert(permission != null);

  final PermissionStatus permission;
  final bool isLocationEnabled;

  @override
  Widget build(BuildContext context) {
    return Container(
        child: Center(
            child: (() {
      if (!isLocationEnabled)    // Check Bool and show different text
        return Text(
          "Off",
        );
      else
        return Text("On");
    }())));
  }
}

updateShouldNotify: (_, __) => true 添加到您的 StreamProvider

By default, StreamProvider considers that the Stream listened uses immutable data. As such, it will not rebuild dependents if the previous and the new value are ==. To change this behavior, pass a custom updateShouldNotify.

ikerfah 是对的,您正在从 Future 创建 Stream,这意味着当 Future 完成时 Stream 将只包含一个事件(基本上,它不是真正意义上的真正“流” ).

FutureBuilder 也不会工作,因为 Future 只会完成一次,所以它也只会触发一次状态更改。

如果this is the plugin you're using,作者似乎没有实现任何东西来为权限更改事件公开一个“真实的”流。我也不会为此屏住呼吸,因为据我所知,iOS 和 Android 都没有广播事件 if/when 权限已更改。

如果您需要disable/enable一些基于权限是否改变的东西,您只需要在 StatefulWidget 中设置一个定期定时器来轮询变化。

class _LocationWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _LocationWidgetState();
  }
}

class _LocationWidgetState extends State<_LocationWidget> {

  PermissionStatus permission;
  bool isLocationEnabled = false;
  Timer _timer;

  @override
  void initState() {
     _timer = Timer.periodic(Duration(seconds:5), (_) {
       var permission = await _location.hasPermission();
       var isLocationEnabled = await _location.serviceEnabled();
       if(permission != this.permission || isLocationEnabled != this.isLocationEnabled)
           setState(() {});
     });  
  }

  @override
  void dispose() {
     _timer.cancel();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        child: Center(
            child: (() {
      if (!isLocationEnabled)    // Check Bool and show different text
        return Text(
          "Off",
        );
      else
        return Text("On");
    }())));
  }

5 秒是否合适由您决定。 initState() 也应该在状态初始化时设置初始 isLocationEnabled/permission 值,而不是等待 5 秒让计时器启动。