Flutter:获取默认上下文?或加载没有上下文的资产?

时间:2018-06-29 21:28:06

标签: flutter

我正在尝试在扩展SearchDelegate的类中加载json文件以搜索其内容。

我有一种加载该文件的方法:

Future<void> loadCountryData() async {
    try {
      String data = await DefaultAssetBundle
          .of(context)
          .loadString("assets/data/countries.json");
      _countries = json.decode(data);
    } catch (e) {
      print(e);
    }
}

不幸的是,这需要一个Buildcontext(上下文),该上下文似乎仅在SearchDelegate构建方法(例如buildActions,buildLeadings等)中可用,而没有外部条件,例如在构造函数中。

https://docs.flutter.io/flutter/material/SearchDelegate-class.html

由于SearchDelegate中的@override xy构建方法随着搜索字段中的每一次更改而被调用,因此我会一遍又一遍地加载我的文件,这当然是不理想的。 我只想在开始时加载一次文件。

有没有一种方法可以获取某种默认的上下文,例如可以在SearchDelegate的构造函数中使用的默认上下文。就像在android中一样(如果我正确记住的话)?

还是可以在没有.of(context)的情况下加载资产文件?

4 个答案:

答案 0 :(得分:1)

由于DefaultAssetBundle是基于InheritedWidget的,因此您将始终需要 传递上下文

of只是基于BuildContext查找窗口小部件树,直到找到DefaultAssetBundle小部件为止。这意味着如果没有DefaultAssetBundle,则无法检索BuildContext对象。

将需要BuildContext传递给您的方法。我可以想象如下情况:

@override
Widget build(BuildContext context) {
  return FutureBuilder(
    future: loadCountryData(context: context),
    builder: (BuildContext context, AsyncSnapshot<JSON> jsonData) {
      if (!jsonData.hasData) {
        return Text('not loaded');
      }
      return Text('loaded'); // here you want to process your data
    },
  );
}

/// I am not sure what your decode returns, so I just called it JSON
/// I thought it would make more sense to return the JSON to use it in build
Future<JSON> loadCountryData({BuildContext context}) async {
  try {
    String data = await DefaultAssetBundle
      .of(context)
      .loadString("assets/data/countries.json");
    return json.decode(data);
  } catch(e) {
    print(e);
    return JSON.empty(); // imagine this exists
  }
}

如您所见,我从BuildContext方法传递了buildFutureBuilder还允许直接在构建树中处理数据。

答案 1 :(得分:0)

您可以将BuildContext作为参数提供给loadCountryData(BuildContext context)

答案 2 :(得分:0)

功能说明

  /// The bundle from the closest instance of this class that encloses
  /// the given context.
  ///
  /// If there is no [DefaultAssetBundle] ancestor widget in the tree
  /// at the given context, then this will return the [rootBundle].
  ///
  /// Typical usage is as follows:
  ///
  /// ```dart
  /// AssetBundle bundle = DefaultAssetBundle.of(context);
  /// ```
  static AssetBundle of(BuildContext context) {
    final DefaultAssetBundle result = context.dependOnInheritedWidgetOfExactType<DefaultAssetBundle>();
    return result?.bundle ?? rootBundle;
  }

因此,您可以简单地使用rootBundle而不是DefaultAssetBundle.of(context)来处理没有上下文的资产。

答案 3 :(得分:0)

有一个获取内置AssetBundle的选项,而无需指定对BuildContext的引用。这是一个如何完成的示例:

import 'package:flutter/services.dart'; // is required

Future<void> loadCountryData() async {
    try {
        // we can access builtin asset bundle with rootBundle
        final data = await rootBundle.loadString("assets/data/countries.json");
        _countries = json.decode(data);
    } catch (e) {
      print(e);
    }
}