New to the Dart Language and been trying to make an app, But i've been stuck on this problem for a while now and can't seem to solve it. I've been trying to read from the content from a Json file and use a random value generator to pick out which info form the Json to display,

ex

name: Roxxxer Email: [email protected]

name: Roxxxer1 Email: [email protected]

But every time I try to display any of these values I get this error:

enter image description here

This is the json class reader(?)

class Recept{
  final String title;
  final String body;

  Recept({this.title, this.body});

  factory Recept.fromJson(dynamic json){
    return Recept( title: json['title'] as String,
                    body: json['body'] as String,

    );
  }

  String toString() {
    return '{ ${this.title}, ${this.body} }';
  }

}

import 'dart:convert';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:randomfood/Recept.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(
      new MaterialApp(
          home: new AwesomeButton()
      )
  );
}

class AwesomeButton extends StatefulWidget {
  @override
  Button createState() => new Button();
}

class Button extends State<AwesomeButton> {

  String test;

  void onPressed() {
    setState(() {
      //This is where the random generator goes in and give a new place in the json file
    });
  }

  Future<String> LoadRecipesFromJson() async{
    return await rootBundle.loadString('assets/test.json');
  }

  Future LoadRecipes() async{
    String jsonString = await LoadRecipesFromJson();
    final jsonResponse = json.decode(jsonString);
    Recept recept = new Recept.fromJson(jsonResponse);

    String ToString() {
      return '${recept.title}';
    }

    test = ToString();
  }

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

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(title: new Text("Random Recipe Generator!"), backgroundColor: Colors.blueGrey),
        body: new Container(
            child: new Center(
                child: new Column(
                    mainAxisAlignment: MainAxisAlignment.spaceAround,

                    children: <Widget>[

                      new Text(test, style: new TextStyle(color: Colors.black,fontStyle: FontStyle.italic, fontSize: 30.0, fontWeight: FontWeight.bold)),
                      new Padding(padding: new EdgeInsets.all(50.0)),
                      new RaisedButton(
                          child: new Text("Random Recept!", style: new TextStyle(color: Colors.white, fontStyle: FontStyle.italic, fontSize: 20.0)),
                          color: Colors.blueGrey,
                          onPressed: onPressed
                      )
                    ]
                )
            )
        )
    );
  }

}


Solution 1: Benjamin

Since you're using a StatefulWidget you need to use the setState() method to update variables, even though you're calling the function in initState. The reason you have to is that you're using asynchronous data. initState isn't going to wait around for the data so you have to update the state yourself. After you update the state, it will call the build method again and rebuild the widget and your Text widget will be using the new value from the test variable.

Also, the new keyword is optional as of Dart 2.0.

CORRECTION: You can put a function inside of another function.

  Future<void> LoadRecipes() async{
    String jsonString = await LoadRecipesFromJson();
    final jsonResponse = json.decode(jsonString);
    Recept recept = new Recept.fromJson(jsonResponse);

    setState(() {
      test = recept.title;
    });
  }


Solution 2: Aman Malhotra

The variable test may not have a value in the beginning as you are asynchronously loading value into test variable. While giving the test variable inside Text(test) widget if test is null, It'll give an error that you are getting right now. So to prevent this from happening just make a slight change in your code change

This

 new Text(test, style: new TextStyle(color: Colors.black,fontStyle: FontStyle.italic, fontSize: 30.0, fontWeight: FontWeight.bold)),

to

 new Text(test??"Loading", style: new TextStyle(color: Colors.black,fontStyle: FontStyle.italic, fontSize: 30.0, fontWeight: FontWeight.bold)),

Now if the value of test is null you'll get Loading as the text otherwise whatever is the value of the test.