'Create List View with Stream Builder

Want to create a list view from live data from server using stream, so create fake stream of data and then save its snapshot in a list to test result, when use that list in ListTile and run app get following error:

The following assertion was thrown building ListTile(dirty): No Material widget found.

ListTile widgets require a Material widget ancestor.

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: SafeArea(
        child: Center(
          child: StreamBuilderPage(),
        ),
      ),
    );
  }
}

class StreamBuilderPage extends StatefulWidget {
  @override
  _StreamBuilderPageState createState() => _StreamBuilderPageState();
}

class _StreamBuilderPageState extends State<StreamBuilderPage> {
  List<int> items = [];
  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
      //Error number 2
      stream: NumberCreator().stream,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return CircularProgressIndicator();
        } else if (snapshot.connectionState == ConnectionState.done) {
          return Text('done');
        } else if (snapshot.hasError) {
          return Text('Error!');
        } else {
          items.add(snapshot.data);
          print(items); //print every second: [0] then [0,1] then [0,1,2] ...
          return ListView.builder(
            itemBuilder: (context, index) {
              return ListTile(
                title: Text(items[index].toString()),
              );
            },
            itemCount: items.length,
          );
        }
      },
    );
  }
}

class NumberCreator {
  NumberCreator() {
    Timer.periodic(Duration(seconds: 1), (timer) {
      //add count to stream
      _controller.sink.add(_count);
      _count++;
    });
  }
  var _count = 1;
  final _controller = StreamController<int>();

  Stream<int> get stream => _controller.stream;

  dispose() {
    _controller.close();
  }
}

What actually cause this error? Thanks community.



Solution 1:[1]

Try this

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: StreamBuilderPage(),
    );
  }
}

class StreamBuilderPage extends StatefulWidget {
  @override
  _StreamBuilderPageState createState() => _StreamBuilderPageState();
}

class _StreamBuilderPageState extends State<StreamBuilderPage> {
  List<int> items = [];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Center(
          child: StreamBuilder(
            //Error number 2
            stream: NumberCreator().stream,
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting) {
                return CircularProgressIndicator();
              } else if (snapshot.connectionState == ConnectionState.done) {
                return Text('done');
              } else if (snapshot.hasError) {
                return Text('Error!');
              } else {
                items.add(snapshot.data);
                print(
                    items); //print every second: [0] then [0,1] then [0,1,2] ...
                return ListView.builder(
                  itemBuilder: (context, index) {
                    return ListTile(
                      title: Text(items[index].toString()),
                    );
                  },
                  itemCount: items.length,
                );
              }
            },
          ),
        ),
      ),
    );
  }
}

class NumberCreator {
  NumberCreator() {
    Timer.periodic(Duration(seconds: 1), (timer) {
      //add count to stream
      _controller.sink.add(_count);
      _count++;
    });
  }
  var _count = 1;
  final _controller = StreamController<int>();

  Stream<int> get stream => _controller.stream;

  dispose() {
    _controller.close();
  }
}

Solution 2:[2]

I think you have to embed ListTile in a Material specific widget such as scaffold. I had a similar issue a few days ago and somewhere the message tells you which widgets may be wrapped around to prevent this error

Solution 3:[3]

StreamBuilder(
  //Error number 2
  stream: FunctionWhichReturnSomething().stream,
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return CircularProgressIndicator();
    } else if (snapshot.connectionState == ConnectionState.done) {
      return Text('done');
    } else if (snapshot.hasError) {
      return Text('Error!');
    } else {
      items.add(snapshot.data);
      print(
          items); //print every second: [0] then [0,1] then [0,1,2] ...
      return ListView.builder(
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(items[index].toString()),
          );
        },
        itemCount: items.length,
      );
    }
  },
)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Raine Dale Holgado
Solution 2 w461
Solution 3 Hee