【问题标题】:Updating listview by API best practice通过 API 最佳实践更新列表视图
【发布时间】:2019-11-21 00:28:29
【问题描述】:

这是我调用 API 来获取 xml 项目的代码。 列表视图按文章更新。

现在,在更改 listview 的变量后,我调用了一次 setState()。

但是,在运行此代码时。 setState() 被无限调用,并不断更新。

我应该如何解决或最佳做法是什么??

class Article{
  String title;
  String url;
  Article() {}
}
List<Article> articles = [];

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;


  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    void _callApi() async{
      final response = await http.get('http://localhost/mamasoku/web/app_dev.php/api/byLatest/1/10');
      if (response.statusCode == 200) {

        var document = xml.parse(response.body);
        var items = document.findAllElements('item');
        print("item number:" + items.length.toString());
        items.forEach((var item) {
          var a = Article();
          a.title = item.findElements('title').single.text;
          a.url = item.findElements('url').single.text;
          articles.add(a);
        });
        setState(() => {});
      }
    }
    _callApi();

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: BodyLayout(), 
    );
  }
}
class BodyLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return _myListView(context);
  }
}
 Widget _myListView(BuildContext context) {


      return ListView.builder(
        itemCount: articles.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(articles[index].title),
          );
        },
      );
    }

void onTapped(var index) {
  print(index);
}

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    setState()之所以被无限调用,是因为setState()会调用build(BuildContext context)方法。

    所以,你应该从 build(BuildContext context) 方法中移除 setState(),并将 _callApi() 方法移到 initState(),

    像这样:

    import 'package:flutter/material.dart';
    import 'dart:ui' as ui;
    import 'package:flutter/services.dart' show rootBundle;
    import 'dart:async';
    import 'dart:typed_data';
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class Article {
      String title;
      String url;
    
      Article() {}
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      int _counter = 0;
      List<Article> articles = [];
    
      void _incrementCounter() {
        setState(() {
          _counter++;
        });
      }
    
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
        _callApi();
      }
    
      void _callApi() async {
    //    final response = await http
    //        .get('http://localhost/mamasoku/web/app_dev.php/api/byLatest/1/10');
    //    if (response.statusCode == 200) {
    //      var document = xml.parse(response.body);
    //      var items = document.findAllElements('item');
    //      print("item number:" + items.length.toString());
    //      items.forEach((var item) {
    //        var a = Article();
    //        a.title = item.findElements('title').single.text;
    //        a.url = item.findElements('url').single.text;
    //        articles.add(a);
    //      });
    //
    //    }
    
      ///  Analog network request
      Future.delayed(Duration(seconds: 10)).then((data){
        articles.add(Article()..title="test1"..url="www.123.com");
        articles.add(Article()..title="test2"..url="www.123.com");
        articles.add(Article()..title="test3"..url="www.123.com");
        articles.add(Article()..title="test4"..url="www.123.com");
        setState(() => {});
      });
    
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: BodyLayout(articles),
        );
      }
    }
    
    class BodyLayout extends StatelessWidget {
      final List<Article> articles;
    
      BodyLayout(this.articles);
    
      @override
      Widget build(BuildContext context) {
        return ListView.builder(
          itemCount: articles.length,
          itemBuilder: (context, index) {
            return ListTile(
              title: Text(articles[index].title),
            );
          },
        );
      }
    }
    
    void onTapped(var index) {
      print(index);
    }
    

    【讨论】:

    • 非常感谢,你完美地解决了我的问题。此示例代码非常完美,值得学习。我明白为什么 setState 被无限调用了。
    【解决方案2】:

    你需要做很多改变来应用最佳实践,你需要分离模型、API调用、逻辑和视图,这样你就可以应用单一责任模式,也推荐使用BloC模式来分离视图中的逻辑并创建一个通用类来处理所有 api 调用,因此将来当您需要对 api 进行类似调用时,您不需要重复代码(DRY 模式),也许您需要应用更多的变化,但现在这些变化应该足够了,但相信我,它会帮助你改进你的应用程序

    【讨论】:

    • 谢谢。我已经习惯了其他框架视图 /mode/ 控制器样式。但现在我在颤抖中挣扎....
    猜你喜欢
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-10
    • 1970-01-01
    • 1970-01-01
    • 2016-03-06
    • 1970-01-01
    相关资源
    最近更新 更多