初始化有状态窗口小部件时,我无法访问服务对象。问题来自context
中的initState
对象。
我正在使用InheritedWidget
在我的main.dart
文件中注入服务对象
void main() async {
final sqflite.Database database = await _openDatabase('db.sqlite3');
runApp(
Services(
database: database,
child: MyApp(),
),
);
}
Services
对象非常简单。它将不仅有database
作为成员。这个想法是,小部件不需要知道是否正在访问本地数据库,本地缓存或远程服务器。
class Services extends InheritedWidget {
final Database database;
const Services({
Key key,
@required Widget child,
@required this.database,
}) : assert(child != null),
assert(database != null),
super(key: key, child: child);
Future<List<models.Animal>> readAnimals() async {
return db.readAnimals(database: this.database);
}
@override
bool updateShouldNotify(InheritedWidget oldWidget) {
return false;
}
static Services of(BuildContext context) {
return context.inheritFromWidgetOfExactType(Services) as Services;
}
}
当我想从数据库中加载所有动物时,麻烦就出在我的_HomePageState
状态。我需要访问Services
对象。我无法访问Services
中的initState
对象,所以我正在使用didChangeDependencies
。从堆栈中删除主页时出现问题。似乎didChangeDependences
被调用,访问上下文对象是非法的。因此,我创建了一个_initialized
标志,可以在didChangeDependencies
中使用该标志以确保仅在第一次加载动物时使用。 这看起来非常优雅。有更好的方法吗?
class _HomePageState extends State<HomePage> {
bool _initialized = false;
bool _loading = false;
List<Animal> _animals;
@override
Widget build(final BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(Strings.of(this.context).appName),
),
body: _HomeBody(
loading: this._loading,
animals: this._animals,
),
);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
if (!this._initialized) {
this._initialized = true;
this._loadAnimals();
}
}
void _loadAnimals() async {
this.setState(() {
this._loading = true;
this._animals = null;
});
final List<Animal> animals = await Services.of(this.context).readAnimals();
this.setState(() {
this._loading = false;
this._animals = animals;
});
}
}
答案 0 :(得分:2)
在这种情况下,可以在构建窗口小部件后使用addPostFrameCallback
实例的WidgetsBinding
来执行一些代码。
_onLayoutDone(_) {
this._loadAnimals();
}
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback(_onLayoutDone);
super.initState();
}