每5分钟或定期刷新Flutter Text小部件内容 [英] Refresh Flutter Text widget content every 5 minutes or periodically

查看:109
本文介绍了每5分钟或定期刷新Flutter Text小部件内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Flutter Text 小部件,其内容是通过外部REST调用填充的。我想通过调用REST端点每5分钟定期刷新一次小部件内容。

I have a Flutter Text widget and its content is populated from an external REST call.I would like to refresh the widget content periodically every 5 mins by calling the REST endpoint.

到目前为止,我设法每5分钟调用一次端点,但是无法使用来自网络的新数据更新/刷新窗口小部件内容。

So far I managed to call the endpoint every 5 mins but unable to update/refresh the widget content with new data from network.

 class PatientCount {
  int count;
  double amount;

PatientCount({this.count, this.amount});

 PatientCount.fromJson(Map<String, dynamic> map)
  : count = map['count'],
    amount = map['amount'];
}

Future<PatientCount> fetchPatientCount() async {

  var url = "http://localhost:9092/hms/patients-count-on-day";

  Map<String, String> requestHeaders = new Map<String, String>();
  requestHeaders["Accept"] = "application/json";
  requestHeaders["Content-type"] = "application/json";

  String requestBody = '{"consultedOn":' + '16112018' + '}';  

  http.Response response =
  await http.post(url, headers: requestHeaders, body: requestBody);

  final statusCode = response.statusCode;
  final Map responseBody = json.decode(response.body);

  if (statusCode != 200 || responseBody == null) {
     throw new FetchPatientCountException(
    "Error occured : [Status Code : $statusCode]");
   }
    return PatientCount.fromJson(responseBody['responseData']. 
    ['PatientCountDTO']);
}    
class MainPage extends StatefulWidget {
  @override
  _MainPageState createState() => _MainPageState();
 }

class _MainPageState extends State<MainPage> {
@override
void initState() {
super.initState();
setState(() {
  const oneSecond = const Duration(seconds: 25);
  new Timer.periodic(oneSecond, (Timer t) => buildCountWidget());
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
    appBar: AppBar(
      elevation: 2.0,
      backgroundColor: Colors.white,
      title: Text('Dashboard'),
    ),
    body: StaggeredGridView.count(
      crossAxisCount: 2,
      crossAxisSpacing: 12.0,
      mainAxisSpacing: 12.0,
      padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
      children: <Widget>[
        _buildTile(
          Padding(
            padding: const EdgeInsets.all(24.0),
            child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      Text(
                        'Today\'s OPD',
                        style: TextStyle(
                            color: Colors.blueAccent, fontSize: 18.0),
                      ),
                      buildCountWidget(),
                    ],
                  ),
                  Material(
                      color: Colors.blue,
                      borderRadius: BorderRadius.circular(24.0),
                      child: Center(
                          child: Padding(
                        padding: const EdgeInsets.all(16.0),
                        child: Icon(Icons.timeline,
                            color: Colors.white, size: 30.0),
                      )))
                ]),
          ),
        ),
      ],
      staggeredTiles: [StaggeredTile.extent(2, 110.0)],
    ));
  }

 Widget _buildTile(Widget child, {Function() onTap}) {
  return Material(
    elevation: 14.0,
    borderRadius: BorderRadius.circular(12.0),
    shadowColor: Color(0x802196F3),
    child: InkWell(
        // Do onTap() if it isn't null, otherwise do print()
        onTap: onTap != null
            ? () => onTap()
            : () {
                print('Not set yet');
              },
        child: child));
  }

 Widget buildCountWidget() {
 Widget vistitCount = new Center(
  child: new FutureBuilder<PatientCount>(
    future: fetchPatientCount(),
    builder: (context, snapshot) {          
      if (snapshot.connectionState == ConnectionState.done) {
        if (snapshot.hasData) {
          print(snapshot.data.count);
          /* below text needs to be updated every 5 mins or so */
          return new Text('#' + snapshot.data.count.toString(),
              style: TextStyle(
                  color: Colors.black,
                  fontWeight: FontWeight.w700,
                  fontSize: 34.0));
        } else if (snapshot.hasError) {
          return new Text("${snapshot.error}");
        }
      }

      // By default, show a loading spinner
      return new CircularProgressIndicator();
    },
  ),
);
return vistitCount;
}
}

buildCountWidget内部方法文本小部件需要用网络中的最新数据刷新。

Inside the buildCountWidget method the Text widget needs to be refreshed with the latest data from the network.

我将实现更改为使用setState,如下所示,仍然没有运气

I changed the implementation to use setState as below, still no luck

class _MainPageState extends State<MainPage> {
  Future<PatientCount> _patientCount;
  Timer timer;
  @override
  void initState() {
    super.initState();
    callApi();
    timer = Timer.periodic(Duration(seconds: 15), (Timer t) => setState(() {}));
  }

  void callApi() {
    setState(() {
      _patientCount = fetchPatientCount();
    });
  }
 ..........................

还更改了如下逻辑,我可以调用REST端点,但是小部件数据不会每25秒更新一次。小部件显示的是旧数据

Also changed the logic as below, with this I am able to call the REST endpoint but the widget data is not getting updated every 25 seconds.The widget is showing the old data .

class _MainPageState extends State<MainPage> {
  Future<PatientCount> _patientCount;
  Timer timer;
  @override
  void initState() {
    super.initState();
    //callApi();
    timer = Timer.periodic(Duration(seconds: 15), (Timer t) => callApi());
  }

  void callApi() {
    setState(() {
      _patientCount = fetchPatientCount();
    });
  }

...........................

根据代码显示的计数相同,计数在25秒后不会增加。但是从后端定期触发Api并将数据返回到UI,但窗口小部件的状态未更改。

As per the code it is showing the same count , the count is not getting incremented after 25 seconds.However from the backend the Api is fired periodically and returning the data to UI, but the state to the widget is not changing.

推荐答案

替换此:

new Timer.periodic(oneSecond, (Timer t) => buildCountWidget());

通过以下方式:

new Timer.periodic(oneSecond, (Timer t) => setState((){}));

它应该可以工作,每次调用setState都会刷新小部件并调用再次使用将来的方法。

And it should work, every time you call setState it'll refresh the widget and will call to the Future method again.

更新

工作正常,如果您将这些更改后,您会注意到如何刷新数据(仅用于测试):

It's working fine, if you make these changes, you will notice how the data is refreshed (just for testing):

        Future<String> fetchPatientCount() async {
          print("fetchPatientCount");
          return DateTime.now().toIso8601String();
        }

        ...

        new FutureBuilder<String>(
                future: fetchPatientCount(),
                builder: (context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.done) {
                    if (snapshot.hasData) {            
                      /* below text needs to be updated every 5 mins or so */
                      return new Text('#' + snapshot.data.toString(),
                          style: TextStyle(
                              color: Colors.black,
                              fontWeight: FontWeight.w700,
                              fontSize:7.0));
                    } else if (snapshot.hasError) {
                      return new Text("${snapshot.error}");
                    }
                  }

如果数据每25秒更改一次,则表明该数据有效,您必须检查 fetchPatientCount 方法。 (在发送 requestBody 之前将数据编码为json)

If the data changes every 25 seconds, it's working , you have to check your fetchPatientCount method. ( encode the data to json before send requestBody)

这篇关于每5分钟或定期刷新Flutter Text小部件内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆