'Variable scope within the Flutter StatefulWidget

I'm trying to access the moviesList inside the build() and results as follows. What is the real issue?

flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following NoSuchMethodError was thrown building MyListScreen(dirty, state:
flutter: _MyListScreenState#21007):
flutter: The getter 'results' was called on null.
flutter: Receiver: null
flutter: Tried calling: results

The code snippet followed as below:

class _MyListScreenState extends State<MyListScreen> {

  MoviesList moviesList;

  _getLatestMovies() {
    APIService.getMoviesNowPlaying().then((response) {
      setState(() {
        final jsonData = json.decode(response.body);
        moviesList = new MoviesList.fromJson(jsonData);
        // moviesList(new MoviesList.fromJson(jsonData));

        for (var i = 0; i < moviesList.results.length; i++) {
          print(moviesList.results[i].title);
        }
      });
    });
  }

  @override
  initState() {
    super.initState();
    _getLatestMovies();
  }

  @override
  Widget build(context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("View Title"),
      ),
      body: ListView.separated(
        padding: EdgeInsets.zero,
        itemCount: moviesList.results.length,
        itemBuilder: (context, index) {
          // return ListTile(title: Text(moviesList.results[index].title));
        },
        separatorBuilder: (context, index) {
          return Divider();
        },
      ));
  }
}


Solution 1:[1]

Use

itemCount: moviesList != null ? moviesList.results.length : 0,

Your build() was getting called before moviesList was initialised, so here we first check for null, if null use 0 as itemCount else use its length.

Solution 2:[2]

Solution (probably one):

The real reason behind the issue wasn't variable scope, rather it was the way async did was completely wrong, a redesign solved the issue. Moved _getLatestMovies(); inside the FutureBuilder.

Improved one pasted below:

  @override
  Widget build(context) {
    var futureBuilder = FutureBuilder(
        future: _getLatestMovies(),
        builder: (context, snapshot) {
          if (snapshot.data != null) {
            return ListView.separated(
                padding: EdgeInsets.zero,

with this move, the FutureBuilder awaits the result from the method and passed onto the ListView as a snapshot.

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
Solution 2