Stream builder 在第一次加载屏幕时未加载所需数据,然后在更改选项卡后正常工作:Flutter

Stream builder not loading desired data at the first loading of the screen, then working as it should after changing tabs : Flutter

我正在使用 Stream 构建器在使用 Flutter 的屏幕上填充不同选项卡的正文内容。流构建器从 Firebase 获取数据并将这些值传递到不同的列表中,这些列表在 listView 构建器中用于显示内容。

屏幕上的选项卡应该会根据上一个屏幕上的选择而改变。这部分效果很好。然而,

问题 1:

在初始加载屏幕时,所有选项卡的内容都显示在最初选择的选项卡下方。只有当我向右滑动一次,即转到其他标签时,我才会在屏幕上看到所需的内容,即相应标签下的相应内容。

问题 2:

如果我从这个屏幕返回到上一个屏幕并再次做出不同的选择...在这个屏幕上打开的第一个选项卡上,我从上一个选项卡中获取内容,该选项卡在点击之前加载后退按钮。只有选择其他选项卡时,我才能获得所需的输出。

这表示编写的代码有效,但仅在特定条件下有效。选项卡完全按预期加载,即使是在第一次尝试时,也只有选项卡下的内容是一个问题……同样,仅在加载的第一个屏幕上。这清楚地表明流生成器有问题,但我似乎无法弄清楚到底是什么。

我使用流生成器的代码布局是:

 body : StreamBuilder(
  
  stream: Firestore.instance
          . //Required Reference//     
          .snapshots(),
  
  builder: (BuildContext context, AsyncSnapshot <QuerySnapshot>snapshot) {
    
    var someData = snapshot.data.documents;
    List<dynamic> someDocs = someData;

    if (snapshot.hasData == null){
      return CircularProgressIndicator(),}


    else if (snapshot.data.documents.length > 0){ 

      RequiredList1 = [];
      ..... More such statements ..........
      RequiredList11 = [];

      for(int i =0; i < someDocs.length; i++){
  
        RequiredList1.add(someData[i]['field1']);
        ....... More such calls ................
        RequiredList11.add(someData[i][field11']);            

      } 
       return WidgetToShowContents
      
       }
      }
     );

唯一值得注意的是,所做的引用包括当前所选选项卡的名称。但是,由于该选项卡显示正确,并且所有其他选项卡也可以正常工作,所以我确信这不是造成问题的原因。

我想过使用 dispose 方法摆脱流生成器来解决问题 2,但我不知道如何使用流生成器实现它,我也不确定这是否会起作用。

你试过把你的 StreamBuilder 翻转过来吗?我知道它的接缝可能并不重要,但我已经看到它有所不同,如果这有帮助,请告诉我。

StreamBuilder(

  stream: Firestore.instance
          . //Required Reference//     
          .snapshots(),

  builder: (BuildContext context, AsyncSnapshot <QuerySnapshot>snapshot) {


    if (snapshot.hasData){
      if(snapshot.data.documents.length > 0){
 var someData = snapshot.data.documents;
    List<dynamic> someDocs = someData;

         RequiredList1 = [];
      ..... More such statements ..........
      RequiredList11 = [];

      for(int i =0; i < someDocs.length; i++){

        RequiredList1.add(someData[i]['field1']);
        ....... More such calls ................
        RequiredList11.add(someData[i]['field11']);            

      } 

      }else{
           return WidgetToShowContents
      }


    }else{
      CircularProgressIndicator();
    }


  }
     );

好吧,经过大量调试,我想通了是什么原因导致第一个tab加载时body中没有得到想要的内容,但是后面的所有tab都没有。

The only other noteworthy thing can be, that the reference made includes the name of the tab that is currently selected. However, since the tab shows appropriately, and all the other tabs work too, I am sure that, that is not something creating the issue.

我所做的是,参考调用取决于当前所选选项卡中的值,即对于不同的选项卡,将提取和显示不同的数据。

 @override
   void initState() {
   super.initState();    
  tabController = TabController(length: subCategoryList.length, vsync: this, initialIndex: 0);
  tabController.addListener(_setActiveTabIndex);
}

void _setActiveTabIndex() {
  activeTabIndex = tabController.index;
  setState(() {
    currentTab = subCategoryList[activeTabIndex].toString(); 
  });
}

现在,我在 initState() 中初始化 tabController 并使用侦听器来了解哪个选项卡当前处于活动状态。在打印这些值时,我了解到在第一次加载屏幕时,'activeTabIndex' 以及 'currentTab' return 空值。当第一次加载第二个屏幕,或返回第一个屏幕并选择另一个选项再次进入此屏幕时,就是这种情况。

因此,只要选择了与第一个选项卡不同的选项卡,它就会 return 在内容中编辑所需的值。

为了解决这个问题,我将 currentTab 的默认值设置为始终根据页面加载时显示的第一个选项卡加载内容。为此,我在 initState() 中添加了一行:

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

  currentTab = subCategoryList[0].toString();
  tabController = TabController(length: subCategoryList.length, vsync: this, initialIndex: 0);
  tabController.addListener(_setActiveTabIndex);
 }

现在,无论何时加载页面,我都会在正文中获得所需的内容,因为在构建用于显示内容的小部件时,这些值已经初始化。