如何在flutter的build方法中调用provider中的方法?

Posted

技术标签:

【中文标题】如何在flutter的build方法中调用provider中的方法?【英文标题】:how to call the method in provider inside the build method in flutter? 【发布时间】:2020-08-11 07:07:45 【问题描述】:

我在类中有一个方法,它扩展了从 API 获取数据的 changeNotifier。现在我想在构建方法中打开页面时调用此方法,但是当我调用该方法时,由于 notifyListeners 方法而重复调用它。我想知道如何只调用一次方法。

ReportProvider.dart

class ReportProvider extends ChangeNotifier

  static DateFormat dateFormat = new DateFormat('dd-MM-yyyy');
  static DateFormat actualDateFormat = new DateFormat("yyyy-MM-dd");
  String _toDate = dateFormat.format(new DateTime.now());
  String _actualToDate = actualDateFormat.format(new DateTime.now());
  String _actualFromDate = actualDateFormat.format(new DateTime.now().subtract(new Duration(days: 7)));
  String _fromDate = dateFormat.format(new DateTime.now().subtract(new Duration(days: 7)));
  bool _progressStatuc = false;
  bool _chartVisible = true;
  bool _errorVisible = false;
  String _errorMessage;

  String get errorMessage => _errorMessage;
  bool get errorVisible => _errorVisible;
  bool get chartVisible => _chartVisible;
  bool get progressStatus => _progressStatuc;
  String get toDate => _toDate;
  String get fromDate => _fromDate;

  List<PieData> _data = new List();

  List<PieData> get data => _data;

  Future<void> getReportData() async
  
    Map<String,dynamic> sessiondata = await new Utilities().getSessionData();
    int shopid = sessiondata['shopid'];
    Map<String,String> reportData = new Map();
    reportData['shopid'] = shopid.toString();
    reportData["fromdate"] = _actualFromDate;
    reportData["todate"] = _actualToDate;
    String token = await new Utilities().getToken();

    Map userHeader = "token": token;
    print(reportData.toString());

    if(await new Utilities().checkInternet())
    
      try
      
        http.Response response = await http.post(EndPointUrl.report,body: reportData,headers: userHeader);
        String message = json.decode(response.body)['message'];
          List<ReportData> data = json.decode(response.body)['data'];
          data.forEach((reportData)
            _data.add(new PieData(reportData.menuname,reportData.itemcount));
          );
          notifyListeners();
      
      catch(error)
      
        _errorMessage = "Server error";
        notifyListeners();
      

    
    else
    
      _progressStatuc = false;
      _chartVisible = false;
      _errorVisible = true;
      _errorMessage = "No Internet Connection";
      notifyListeners();
    
  






报告.dart

class Report extends StatefulWidget

  @override
  State<StatefulWidget> createState() 
    return ReportState();
  



class ReportState extends State<Report>

  @override
  Widget build(BuildContext context) 

    final reportProvider = Provider.of<ReportProvider>(context);

    reportProvider.getReportData();
    //yprint(reportProvider.data.toString());
    if(reportProvider.errorMessage != null &&  reportProvider.errorMessage.contains("Internet"))
    
      showDialog(
        context: context,
        builder: (BuildContext context)
          return AlertDialog(
            title: Text("Error"),
            content: Text("$reportProvider.errorMessage"),
            actions: <Widget>[
              FlatButton(
                child: Text("ok"),
                onPressed: ()
                  Navigator.pop(context);
                ,
              )
            ],
          );
        );
    
   return Stack(
     children: <Widget>[
       Column(
         crossAxisAlignment: CrossAxisAlignment.start,
         children: <Widget>[
           Container(
             margin: EdgeInsets.fromLTRB(8, MediaQuery.of(context).size.height*0.05,0, 0),
             child: Text(
               "Report",
               style: TextStyle(fontSize: 28,color: Colors.black),
             ),
           ),
           Row(
             children: <Widget>[
               Expanded(
                 flex: 3,

                  child: Container(
                    margin: EdgeInsets.fromLTRB(8, 8, 0, 0),
                    child: GestureDetector(
                     onTap: ()
                       reportProvider.selectDate(context, "fromdate");
                     ,
                     child: Text(
                       "$reportProvider.fromDate",
                       style: TextStyle(color: Colors.black,fontSize: 16),
                     ),
                 ),
                  ),
               ),
               Expanded(
                 flex: 1,
                  child: Text(
                   "To",
                   style: TextStyle(fontSize: 16,color: Colors.grey),
                 ),
               ),
               Expanded(
                 flex: 3,
                  child: GestureDetector(
                   onTap: ()
                     reportProvider.selectDate(context, "todate");
                   ,
                   child: Text(
                     "$reportProvider.toDate",
                     style: TextStyle(color: Colors.black,fontSize: 16),
                   ),
                 ),
               ),
               Expanded(
                 flex: 1,
                  child: GestureDetector(
                   onTap: (),
                   child: Icon(
                     Icons.check,
                     color: Theme.of(context).accentColor,
                   ),
                 ),
               )

             ],
           ),
          //  Visibility(
          //    visible: reportProvider.chartVisible,
          //     child: charts.PieChart<PieData>(

          //    ),
          //  ),
           Expanded(
              child: Visibility(
               visible: reportProvider.errorVisible,
               child: Container(
                 alignment: Alignment.center,
                 child: Column(
                   crossAxisAlignment: CrossAxisAlignment.center,
                   mainAxisAlignment: MainAxisAlignment.center,
                   children: <Widget>[
                     SvgPicture.asset('assets/images/undraw_report.svg',width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height*0.40),
                                    Text(
                                      "No Reports are available",
                                      style: TextStyle(color: Colors.black,fontSize: 20),
                                    )
                   ],
                 ),
               ),
             ),
           )

         ],
       ),

     ],
   );
  



【问题讨论】:

更改为 final reportProvider = Provider.of&lt;ReportProvider&gt;(context, listen: false); 可能会为您解决问题。 【参考方案1】:

根据documentation,每次发生变化时都会调用 build() 方法。如果您希望只触发一次调用,您可以使用initState() 方法并添加一些帮助方法来更新 UI。一个例子可以在这里找到:https://flutter.dev/docs/get-started/flutter-for/android-devs#what-is-the-equivalent-of-runonuithread-in-flutter

上一个链接的异步加载示例,特别注意loadData方法:

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() 
  runApp(SampleApp());


class SampleApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Sample App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SampleAppPage(),
    );
  


class SampleAppPage extends StatefulWidget 
  SampleAppPage(Key key) : super(key: key);

  @override
  _SampleAppPageState createState() => _SampleAppPageState();


class _SampleAppPageState extends State<SampleAppPage> 
  List widgets = [];

  @override
  void initState() 
    super.initState();

    loadData();
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text("Sample App"),
      ),
      body: ListView.builder(
        itemCount: widgets.length,
        itemBuilder: (BuildContext context, int position) 
          return getRow(position);
        ,
      ),
    );
  

  Widget getRow(int i) 
    return Padding(
      padding: EdgeInsets.all(10.0),
      child: Text("Row $widgets[i]["title"]"),
    );
  

  Future<void> loadData() async 
    String dataURL = "https://jsonplaceholder.typicode.com/posts";
    http.Response response = await http.get(dataURL);
    setState(() 
      widgets = json.decode(response.body);
    );
  


【讨论】:

在您的示例中,您没有使用提供者

以上是关于如何在flutter的build方法中调用provider中的方法?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter局部刷新方法

在 Flutter 中,当子组件的 build 方法中没有回调时,如何从子组件中读取数据?

build 方法多久调用一次?

Flutter组件(Widget)的局部刷新方式

Flutter生命周期

mvn 编译报错mavn sun.security.validator.ValidatorException: PKIX path building failed: sun.security.prov