我想制作一个连接服务器并发送不同请求,获取响应等的应用程序。为此,我有一个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(),
);
}
}
}