9

我想在开始时完成get对服务器的请求以获取我的应用程序的数据。我阅读了几个描述如何在构建小部件后运行方法的主题。但所有这些都是描述provider不使用时的情况。而且我不确定在小部件中执行此请求是否是个好主意。

我尝试了几种方法,但都没有成功。这是我的代码:

void main() async {
      runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ChangeNotifierProvider<TenderApiData>(
          builder: (_) => TenderApiData(), child: HomePage()),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(appBar: AppBar(), body: MainContainer());
  }

}

class TenderApiData with ChangeNotifier {
  String access_token;
  List<Map<String, String>> id_names;

  String access_token_url =  "https://...";

  getApiKey() async { // I need to call this method at app start up 
    var response = await http
        .post(access_token_url, headers: {"Accept": "application/json"});
    if (response.statusCode == 200) {
      access_token = json.decode(response.body)['access_token'];
      notifyListeners();
    }
  }

}

class MyTestWidget extends StatefulWidget {
  MyTestWidgetState createState() => MyTestWidgetState();

}

class MyTestWidgetState extends State<MyTestWidget> {

  bool isKeyGetted = false;

  // before I used this when I extracted data on click event. 
  // I am not sure that it's needed now
  @override
  void didChangeDependencies() { 
    if (!isKeyGetted) {
      Provider.of<TenderApiData>(context).getApiKey();
      isKeyGetted = !isKeyGetted;
    }
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {

    if (!isKeyGetted) {
      Provider.of<TenderApiData>(context).getApiKey();
      isKeyGetted = !isKeyGetted;
    }

    var result = Provider.of<TenderApiData>(context).access_token;
    var test = Provider.of<TenderApiData>(context).id_names;
    return Column(
      children: <Widget>[
        RaisedButton(
          onPressed: Provider.of<TenderApiData>(context).getRegionsList,
          child: Text("get regions"),
        ),
      ],
    );
  }


}

class MainContainer extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Table(
      children: [
        TableRow(children: [
          Row(
            children: <Widget>[
              Container(child: MyTestWidget()),
              Container(child: Text("Regions"),),

              Expanded(child: SelectRegions(),  )
            ],
          )
        ]),
        TableRow(children: [
          Row(
            children: <Widget>[
              Text("Label"),
              Text("Value"),
            ],
          )
        ]),
      ],
    );
  }
}
4

4 回答 4

5

您可以存储TenderApiData为 的成员MyApp,在构造函数中进行启动调用MyApp并将现有实例传递给后代。
这是它的外观:

class MyApp extends StatelessWidget {

  final TenderApiData _tenderApiData = TenderApiData();

  MyApp() {
    _tenderApiData.getApiKey();
  };

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ChangeNotifierProvider<TenderApiData>(
          builder: (_) => _tenderApiData, child: HomePage()),
    );
  }
}

其他类将保持不变。

另一种选择是将TenderApiData作为构造函数参数传递给MyApp,使其更具可测试性。

void main() {
  final TenderApiData tenderApiData = TenderApiData();
  tenderApiData.getApiKey(); // call it here or in MyApp constructor - now it can be mocked and tested
  runApp(MyApp(tenderApiData));
}

class MyApp extends StatelessWidget {

  final TenderApiData _tenderApiData;

  MyApp(this._tenderApiData);

// ...
于 2019-08-02T08:13:57.653 回答
1

您可以在TenderApiDatado trigger 自定义逻辑上添加构造函数:

class TenderApiData with ChangeNotifier {
  TenderApiData() {
    // TODO: call `getApiKey`
  }
}
于 2019-08-02T09:20:58.957 回答
0

你可以FutureProvider使用价值。

将方法 api 分离到服务 (my_service.dart):

class MyService {
  Future<String> getApiKey() async {
    // I need to call this method at app start up
    var response = await http
        .post(access_token_url, headers: {"Accept": "application/json"});
    if (response.statusCode == 200) {
      return json.decode(response.body)['access_token'];
    }
  }
}

而不是从 MyApp 调用

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return FutureProvider<String>.value(
      value: MyService().getApiKey(),
      child: HomePage(),
    );
  }
}

在主页中:

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    String token = Provider.of<String>(context);
    return Scaffold();
  }
}
于 2019-12-18T10:26:50.740 回答
0

您也可以只使用一个布尔标志来只运行该方法一次

提供者

import 'screen.abstract.dart';

class MyProvider with ChangeNotifier {
  _hasInitialized = false;

  // This will only be run once, when called
  fetchApiOnce() {
    if (_hasInitialized) {
      return;
    }
    _hasInitialized = true;

    /* DO STUFF */
  }
}
于 2021-08-02T14:49:14.170 回答