在小部件A的build方法中访问InheritedWidget会导致小部件A的重建,从而导致无限循环

时间:2019-08-03 11:26:09

标签: flutter dart

我想制作一个连接服务器并发送不同请求,获取响应等的应用程序。为此,我有一个Client类(不是小部件),该类可以处理所有网络内容。我使用块模式来封送对客户端的请求并获取响应。该Client实例应该在窗口小部件树上都是可访问的,因此我使用InheritedWidget。我的想法是,用户打开应用程序后首先看到的是启动屏幕,当建立与服务器的连接时,该屏幕应更改为其他页面。我订阅了SplashScreen的build方法中的响应流,并在收到响应时导航到其他页面,但是由于某种原因,访问InheritedWidget会触发SplashScreen的重建,从而导致访问InheritedWidget并导致重建等等。很明显,stream开始抱怨我已经订阅了它。我不会在任何地方更改InheritedWidget,并且不会调用updateShouldNotify,并且无论如何我都将其设置为返回false。这是最小的可复制示例。显然,它不执行任何实际的网络通信,但可以演示我想说的话。

var client = ClientInheritedData.of(context).client导致重建。如果我评论它并使用客户端的行,则不会触发重建。

class Client {

  StreamController<int> _eventStreamController;
  StreamSink<int> get eventSink => _eventStreamController.sink;
  Stream<int> _eventStream;

  StreamController<String> _responseStreamController;
  StreamSink<String> _responseSink;
  Stream<String> get responseStream => _responseStreamController.stream;

  Client() {
    _eventStreamController = StreamController();
    _eventStream = _eventStreamController.stream;

    _responseStreamController = StreamController<String>();
    _responseSink = _responseStreamController.sink;

    _eventStream.listen((event) async {
      if (event == 1) {
        await Future.delayed(Duration(seconds: 2)); // simulate some work
        _responseSink.add('Connected!');
      }
    });
  }
}

void main() => runApp(ClientInheritedData(Client(), MyApp()));

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      theme: ThemeData(
        primarySwatch: Colors.green,
      ),
      initialRoute: '/',
      onGenerateRoute: RouteGenerator.generate,
    );
  }
}

class SplashScreen extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    var client = ClientInheritedData.of(context).client;
    client.eventSink.add(1);
    client.responseStream.listen((response) {
      Navigator.of(context).pushNamed('/Sign Up');
    });

    return Scaffold(
      appBar: AppBar(
        title: Text('Splash Screen'),
      ),
      body: Center(
        child: Text('Greetings!'),
      ),
    );
  }
}

class SignUp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Sign Up'),
      ),
      body: Center(
        child: Text('Hey man'),
      ),
    );
  }
}

class ClientInheritedData extends InheritedWidget {

  final Client client;

  const ClientInheritedData(this.client, Widget child) : super(child: child);

  static ClientInheritedData of(BuildContext context) {
    return context.inheritFromWidgetOfExactType(ClientInheritedData) as ClientInheritedData;
  }

  @override
  bool updateShouldNotify(InheritedWidget oldWidget) {
    return false;
  }
}

class RouteGenerator {

  static Route<dynamic> generate(RouteSettings settings) {
    switch (settings.name) {
      case '/':
        return MaterialPageRoute(
          builder: (context) => SplashScreen(),
        );
      case '/Sign Up':
        return MaterialPageRoute(
          builder: (context) => SignUp(),
        );
    }
  }
}

0 个答案:

没有答案