flutter - 创建 StatefulWidget 时访问 Flutter 上下文

标签 flutter dart

在初始化有状态小部件时,我在访问服务对象时遇到问题。问题来自于 context 对象在 initState 中不可用。

我正在使用 InheritedWidget 在我的 main.dart 文件中注入(inject)服务对象,如下所示

void main() async {
  final sqflite.Database database = await _openDatabase('db.sqlite3');
  runApp(
    Services(
      database: database,
      child: MyApp(),
    ),
  );
}

Services 对象非常简单。它不仅仅是数据库作为成员。这个想法是,小部件不需要知道是否正在访问本地数据库、本地缓存或远程服务器。

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 对象。我无法访问 initState 中的 Services 对象,因此我使用 didChangeDependency。当主页从堆栈中删除时就会出现问题。看起来 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;
    });
  }
}

最佳答案

对于这种情况,您可以使用 WidgetsBinding 实例的 addPostFrameCallback 在构建小部件后执行一些代码。

  _onLayoutDone(_) {
     this._loadAnimals();
  }

  @override
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback(_onLayoutDone);
    super.initState();
  }

关于flutter - 创建 StatefulWidget 时访问 Flutter 上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56729848/

相关文章:

json - 从 Firebase Datasnapshot 获取 JSON 键值

flutter - 在 CustomScrollView 中使用 PageView

Flutter - 避免 ListView 重建

dart - 我怎么知道聚合物 Dart 何时完全初始化?

flutter - 如何在 Dart 中获取某物的类型?

flutter - 在 Flutter 中使用 Google map 和容器堆叠 Widget

android - Flutter VSCode:调试错误:无法使用BuildSessionServices.createFileHasher()创建FileHasher类型的服务

python - 是否可以使用Flutter中的remove.bg API开发应用程序?

dart - 启动画面和 flutter 中的一次介绍

flutter - Flutter:如何通过从值中搜索来从列表中获取索引?