首页 > 解决方案 > 创建 StatefulWidget 时访问 Flutter 上下文

问题描述

初始化有状态小部件时,我无法访问服务对象。问题来自该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;
    });
  }
}

标签: flutterdart

解决方案


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

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

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

推荐阅读