Я бы предложил вместо вызова метода для загрузки данных в методе initState
вашего класса использовать виджет FutureBuilder
.Если вы возвращаете новый FutureBuilder
из вашего Навигационного ящика, он должен вызывать вашу службу каждый раз, когда создается новый, и, как правило, в любом случае является лучшим способом выполнения асинхронных запросов.
Вот очень простой пример.Он не очень хорошо работает (или несколько других вещей - на такие вещи тратится столько времени), но он должен иллюстрировать концепцию.
Обратите внимание, что вместо «обновления виджета»он просто создает новый виджет.Из-за того, как флаттер делает что-то, это должно быть относительно производительным, особенно потому, что вы делаете это не все время, а только тогда, когда пользователь выбирает что-то из меню навигации.
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() => new MyAppState();
}
class MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new TextPage(text: "Home!"),
);
}
}
Map<int, int> _nums = Map();
class TextPage extends StatelessWidget {
final String text;
const TextPage({Key key, @required this.text}) : super(key: key);
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new PreferredSize(
child: new Container(),
preferredSize: Size.fromHeight(10.0),
),
body: new Center(
child: new Text(text),
),
drawer: new Builder(
builder: (context) => Material(
child: new SafeArea(
child: Column(
children: <Widget>[
new FlatButton(
onPressed: () {
Navigator.pushReplacement(
context, new MaterialPageRoute(builder: (context) => _getDrawerItemWidget(1)));
},
child: Text("First item"),
),
new FlatButton(
onPressed: () {
Navigator.pushReplacement(
context, new MaterialPageRoute(builder: (context) => _getDrawerItemWidget(2)));
},
child: Text("Second item"),
),
],
),
),
),
),
);
}
_getDrawerItemWidget(int i) {
return new FutureBuilder<String>(
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.data != null) {
return new TextPage(text: snapshot.data);
} else {
return new TextPage(text: "Loading.");
}
},
future: () async {
var num = _nums.putIfAbsent(i, () => 0);
_nums[i] = num + 1;
String toReturn = "You retrieved number $i for the $num time";
return await Future.delayed<String>(Duration(seconds: 1), () => toReturn);
}(),
);
}
}
Теоретически вы можете это сделатьСделайте что-то другое, сохраняя ссылки GlobalKey и используя их для вызова метода дочернего виджета, если он соответствует текущему выбору, чтобы обновить его, но это обычно плохая идея во флаттере - лучшие практики рекомендуют передавать данные вниз в дереве виджетоввместо вызова функций вниз.Если вам нужно использовать GlobalKeys, вы можете сделать рефакторинг, чтобы сделать что-то лучше.