提供程序重建小部件,但在“热重启”之前啥都没有显示

Posted

技术标签:

【中文标题】提供程序重建小部件,但在“热重启”之前啥都没有显示【英文标题】:Provider rebuilds the widget, but nothing shows up until a "Hot restart"提供程序重建小部件,但在“热重启”之前什么都没有显示 【发布时间】:2020-12-21 19:36:20 【问题描述】:

我正在构建一个颤振应用程序,我从未来获得了一些数据,我还通过 changenotifier 获得了相同的数据。那么逻辑是,虽然某些对象没有数据,因为它在等待未来,然后显示一个旋转的圆圈。我已经在应用程序中完成了这项工作,并且当对象没有接收到数据时,我有一个名为 Loading() 的小部件。我遇到的问题是我得到了数据,但它没有显示任何内容。

数据正确显示,直到我执行应用程序的热刷新。大写的 R 而不是小写的 r。不同之处在于它会启动应用程序并删除所有聚合数据。

当这种情况发生时,似乎数据填充了对象,但我假设它变得不为空,这意味着 [] 为空但不为空,并且“太快”显示数据,这反过来又不显示此小部件,直到我重新启动“r”,它显示了上面的屏幕截图。

这是有问题的代码。

import 'package:disc_t/Screens/LoggedIn/Classes/classTile.dart';
import 'package:disc_t/Screens/LoggedIn/Classes/classpage.dart';
import 'package:disc_t/Screens/LoggedIn/Classes/classpageroute.dart';
import 'package:disc_t/Services/database.dart';
import 'package:disc_t/models/user.dart';
import 'package:disc_t/shared/loading.dart';
import 'package:flutter/material.dart';
import 'package:morpheus/page_routes/morpheus_page_route.dart';
import 'package:provider/provider.dart';

class ClassList extends StatefulWidget 
  @override
  _ClassListState createState() => _ClassListState();


class _ClassListState extends State<ClassList> 
  @override
  void initState() 
    ClassDataNotifier classdatanotif =
        Provider.of<ClassDataNotifier>(context, listen: false);
    // final user = Provider.of<User>(context);
    // getTheClasses(classdatanotif);
    // List<ClassData> d = classes;
  

  @override
  Widget build(BuildContext context) 
    ClassDataNotifier classdatanotif = Provider.of<ClassDataNotifier>(context);

    List<ClassData> cData = Provider.of<List<ClassData>>(context);



    bool rebd = false;

    Widget checker(bool r) 
      if (cData == null) 
        return Loading();
       else 
        if (rebd == false) 
          setState(() 
            rebd = true;
          );

          rebd = true;

          return checker(rebd);

          // return Text("Still Loading");
         else 
          return PageView.builder(
              scrollDirection: Axis.horizontal,
              itemCount: cData.length,
              // controller: PageController(viewportFraction: 0.8),
              itemBuilder: (context, index) 
                return Hero(
                  tag: cData[index],
                  child: GestureDetector(
                    onTap: () 
                      // Navigator.of(context).push(ClassPageRoute(cData[index]));
                      Navigator.push(
                          context,
                          MorpheusPageRoute(
                              builder: (context) =>
                                  ClassPage(data: cData[index]),
                              transitionToChild: true));
                    ,
                    child: ClassTile(
                      classname: cData[index].classname,
                      description: cData[index].classdescription,
                      classcode: cData[index].documentID,
                    ),
                  ),
                );
              );
        
      
    

    
    return checker(rebd);
  

这是提供者的实现方式

void main() => runApp(MyApp());

class MyApp extends StatelessWidget 
  // This widget is the root of your application.

  // final DatabaseService ds = DatabaseService();
  @override
  Widget build(BuildContext context) 
    return MultiProvider(
      providers: [
        StreamProvider<User>.value(
          value: AuthService().user,
          // child: MaterialApp(
          //   home: Wrapper(),
          // ),
        ),
        ChangeNotifierProvider<ClassDataNotifier>(
          create: (context) => ClassDataNotifier(),
        ),
        FutureProvider(
          create: (context) => DatabaseService().fetchClassdata,
        )
      ],
      child: MaterialApp(home: Wrapper()),
    );
  

这是运行以获取数据的函数

Future<List<ClassData>> get fetchClassdata async 
    QuerySnapshot snapshot = await classesCollection.getDocuments();

    List<ClassData> _classList = List<ClassData>();

    snapshot.documents.forEach((element) async 
      QuerySnapshot pre = await Firestore.instance
          .collection("Classes")
          .document(element.documentID)
          .collection("Pre")
          .getDocuments();

      List<Preq> _preList = List<Preq>();

      pre.documents.forEach((preClass) 
        Preq preqData = Preq.fromMap(preClass.data);

        if (preClass.data != null) 
          _preList.add(preqData);
        
      );

      ClassData data =
          ClassData.fromMap(element.data, element.documentID, _preList);

      if (data != null) 
        _classList.add(data);
      
    );

    return _classList;
  

【问题讨论】:

如果有人对如何解决这个问题有任何提示,请告诉我,因为我尝试了很多事情,但我似乎无法到达任何地方。我什至在自己收到数据后尝试重建小部件,但没有成功。 【参考方案1】:

我觉得你provider的逻辑没问题,问题出在一行

snapshot.documents.forEach((element) async 
...

forEach 不是 Future(它里面的东西是未来,因为异步,但方法本身不是)所以代码第一次运行,它到达 forEach,它对每个值执行自己的未来并传播到下一行代码,返回,但列表为空,因为 forEach 尚未完成。

对于这种情况有一个特殊的Future.forEach,所以你可以在运行下一行之前等待 value 方法

Future<List<ClassData>> get fetchClassdata async 
QuerySnapshot snapshot = await classesCollection.getDocuments();

List<ClassData> _classList = List<ClassData>();

await Future.forEach(snapshot.documents, (element) async 
  QuerySnapshot pre = await Firestore.instance
      .collection("Classes")
      .document(element.documentID)
      .collection("Pre")
      .getDocuments();

  List<Preq> _preList = List<Preq>();

  pre.documents.forEach((preClass) 
    Preq preqData = Preq.fromMap(preClass.data);

    if (preClass.data != null) 
      _preList.add(preqData);
    
  );

  ClassData data =
      ClassData.fromMap(element.data, element.documentID, _preList);

  if (data != null) 
    _classList.add(data);
  
);

return _classList;

这是一个similar problem,提供者带有一个forEach。也许它可以帮助您更好地理解

【讨论】:

哦,我的天哪,我已经想了好几天了。谢谢谢谢谢谢谢谢。一直在跳过它并做其他事情

以上是关于提供程序重建小部件,但在“热重启”之前啥都没有显示的主要内容,如果未能解决你的问题,请参考以下文章

流不重建小部件

使用提供程序包 FLUTTER 关闭应用程序后保存状态

如何使用提供程序包收听更改并在颤振中重建小部件?

在小部件构建完成之前运行方法?

Flutter - setState 不更新内部有状态小部件

Flutter BLoC - 状态不会触发小部件重建