Flutter - Providers 和 Future 调用,如何共享同一个实例?

如何解决Flutter - Providers 和 Future 调用,如何共享同一个实例?

我正在学习 Flutter,但有些东西我无法理解。 我用一个包(infine_scroll_pagination)实现了一个无限滚动分页, 它工作正常,但此 Package 获取的数据来自 Future 调用,该调用从 WEB 获取数据,并在我的 Provider Class 中对其进行解析。>

我的问题是,data 加载的 Infinite Scroll widget 无法在其 state 中的其他任何地方访问。

示例: 让我们以一次 contact list 加载 10 个联系人:

class ContactsBody extends StatefulWidget {
  @override
  _ContactsBodyState createState() => _ContactsBodyState();
}

class _ContactsBodyState extends State<ContactsBody> {
  static const _pageSize = 10;
  final PagingController<int,Contact> pagingController =
      PagingController(firstPageKey: 0);

  @override
  void initState() {
    super.initState();
    pagingController.addPageRequestListener((pageKey) {
      _fetchPage(pageKey);
    });
  }

  Future<void> _fetchPage(int pageKey) async {
    try {
      final newItems = await ContactsService().fetchContactsPaged(pageKey,_pageSize);
      final isLastPage = newItems.length < _pageSize;

      if (isLastPage) {
        pagingController.appendLastPage(newItems.contacts);
      } else {
        final nextPageKey = pageKey + 1;
        pagingController.appendPage(newItems.contacts,nextPageKey);
      }
    } catch (error) {
      pagingController.error = error;
    }
  }
  @override
  Widget build(BuildContext context) {
    return ContactsList(pagingController);
  }

  @override
  void dispose() {
    pagingController.dispose();
    super.dispose();
  }

所以基本上这个 Infinite Scroll 包将获取我的联系人,一次 10 个,这里是我的 ContactsService 调用:

 Future<Contacts> fetchContactsPaged(int pageKey,int pageSize) async {
    final response = await http.get(.....);

    if (response.statusCode == 200) {
    return Contacts.fromJson(jsonDecode(response.body));
    } else {
      throw Exception('Failed to load contacts');
    }
  }

最后,正如您在上面看到的那样,它使用其工厂方法“Provider class”初始化我的 fromJson()(联系人),并返回 parsed data

现在我的Provider class

class Contacts extends ChangeNotifier {
      List<Contact> _contacts = <Contact>[];
    
      Contacts();
    
      factory Contacts.fromJson(final Map<String,dynamic> json) {
        final Contacts contacts = Contacts();
        if (json['data'] != null) {
          json['data'].forEach((contact) {
            contacts.add(Contact.fromJson(contact));
          });
        }
        return contacts;
      }

  void add(final Contact contact) {
    this._contacts.add(contact);
    this.notifyListeners();
  }

我在这里遇到的问题是,当加载 Inifinite Scroll listView 时,例如我更改了单个联系人的 state(例如可以将联系人设置为收藏),>

如何访问 SAME instancContacts() classe,FUTURE 调用已初始化,以便我可以访问该类中数据的 current state

当然,如果我将更改 POST 到 API,并在需要的地方重新获取新值,我将获得数据的更新状态,但我想了解如何访问相同的数据在这里实例并使当前数据在应用程序内随处可用

解决方法

编辑:我删除了原始答案,以便更好地说明 OP 想要实现的目标。

我在 GitHub 上做了一个 repo 来尝试向您展示您想要实现的目标:https://github.com/Kobatsu/stackoverflow_66578191

您的代码中有一些令人困惑的地方:

  • 何时创建对象的实例(ContactsService、Contacts)
  • 提供程序使用
  • (访问 pagingController 的列表?)
  • 解析 JSON / 使用工厂方法

存储库结果如下: enter image description here

当您更新列表时(通过向下滚动),黄色容器会更新联系人数量和收藏夹数量。 如果您点击某个联系人,它就会成为收藏夹,并且黄色容器也会更新。

我对存储库进行了评论,以向您解释每个部分。

注意:您代码中的 Contacts 类变成了我的 ContactProvider。

进行 API 调用的 ContactsService 类:

class ContactsService {
  static Future<List<Contact>> fetchContactsPaged(
      int pageKey,int pageSize) async {
    // Here,you should get your data from your API

    // final response = await http.get(.....);
    // if (response.statusCode == 200) {
    //   return Contacts.fromJson(jsonDecode(response.body));
    // } else {
    //   throw Exception('Failed to load contacts');
    // }

    // I didn't do the backend part,so here is an example
    // with what I understand you get from your API:
    var responseBody =
        "{\"data\":[{\"name\":\"John\",\"isFavorite\":false},{\"name\":\"Rose\",\"isFavorite\":false}]}";
    Map<String,dynamic> decoded = json.decode(responseBody);
    List<dynamic> contactsDynamic = decoded["data"];

    List<Contact> listOfContacts =
        contactsDynamic.map((c) => Contact.fromJson(c)).toList();

    // you can return listOfContacts,for this example,I will add 
    // more Contacts for the Pagination plugin since my json only has 2 contacts
    for (int i = pageKey + listOfContacts.length; i < pageKey + pageSize; i++) {
      listOfContacts.add(Contact(name: "Name $i"));
    }
    return listOfContacts;
  }
}

提供者的使用:

Consumer<ContactProvider>(
        builder: (_,foo,__) => Container(
              child: Text(
                  "${foo.contacts.length} contacts - ${foo.contacts.where((c) => c.isFavorite).length} favorites"),padding: EdgeInsets.symmetric(
                  horizontal: 20,vertical: 10),color: Colors.amber,)),Expanded(child: ContactsBody())
  ]),)

ContactsBody 类中的获取页面方法,我们将联系人添加到我们的 ContactProvider 中:

  Future<void> _fetchPage(int pageKey) async {
    try {
      // Note : no need to make a ContactsService,this can be a static method if you only need what's done in the fetchContactsPaged method
      final newItems =
          await ContactsService.fetchContactsPaged(pageKey,_pageSize);
      final isLastPage = newItems.length < _pageSize;
      if (isLastPage) {
        _pagingController.appendLastPage(newItems);
      } else {
        final nextPageKey = pageKey + newItems.length;
        _pagingController.appendPage(newItems,nextPageKey);
      }

      // Important : we add the contacts to our provider so we can get
      // them in other parts of our app
      context.read<ContactProvider>().addContacts(newItems);
    } catch (error) {
      print(error);
      _pagingController.error = error;
    }
  }

ContactItem 小部件,我们在其中更新最喜欢的状态并通知听众:

class ContactItem extends StatefulWidget {
  final Contact contact;
  ContactItem({this.contact});

  @override
  _ContactItemState createState() => _ContactItemState();
}

class _ContactItemState extends State<ContactItem> {
  @override
  Widget build(BuildContext context) {
    return InkWell(
        child: Padding(child: Row(children: [
          Expanded(child: Text(widget.contact.name)),if (widget.contact.isFavorite) Icon(Icons.favorite)
        ]),padding: EdgeInsets.symmetric(vertical: 8,horizontal: 10),),onTap: () {
          // the below code updates the item
          // BUT others parts of our app won't get updated because
          // we are not notifying the listeners of our ContactProvider !
          setState(() {
            widget.contact.isFavorite = !widget.contact.isFavorite;
          });

          // To update other parts,we need to use the provider
          context.read<ContactProvider>().notifyContactUpdated(widget.contact);
        });
  }
}

还有 ContactProvider :

class ContactProvider extends ChangeNotifier {
  final List<Contact> _contacts = [];
  List<Contact> get contacts => _contacts;

  void addContacts(List<Contact> newContacts) {
    _contacts.addAll(newContacts);
    notifyListeners();
  }

  void notifyContactUpdated(Contact contact) {
    // You might want to update the contact in your database,// send it to your backend,etc...
    // Here we don't have these so we just notify our listeners :
    notifyListeners();
  }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res