0

My code is working fine, but I don't know why the variable : Map<String, dynamic> dataJsonObject; return "null" when I build my app with adb (in android studio code). But then if I do a hot reload or a hot restart, my variable "dataJsonObject" return me the correct value. How do I get the correct value to return to me when I build the code the first time. Thank you

my code

import 'package:flutter/material.dart';
import 'dart:convert'; //(jsonDecode)
import 'package:flutter/services.dart'; // (loadJson)
import 'package:flutter/foundation.dart'; //(debugPrint)

class ProverbDisplay extends StatefulWidget {
  final int myId;
  final String myCountry;
  const ProverbDisplay(this.myId, this.myCountry);

  @override
  _ProverbDisplayState createState() => _ProverbDisplayState();
}

class _ProverbDisplayState extends State<ProverbDisplay> {
  Map<String, dynamic> dataJsonObject;

  //Get JSON
  Future getJsonProverb() async {
    final String rawJson = await rootBundle.loadString('assets/json/data.json');
    dataJsonObject = await jsonDecode(rawJson);
    return dataJsonObject;
  }

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

  @override
  Widget build(BuildContext context) {
    debugPrint(' jsonData : $dataJsonObject'); //Return null

    return Container(
      color: Colors.blue,
      height: 250,
      child: Row(
        children: [
          Container(
            width: 300,
            child: PageView.builder(itemBuilder: (context, index) {
              return Text("$dataJsonObject");
            }),
          ),
        ],
      ),
    );
  }
}


1 Answers1

0

You are executing getJsonProverb() in init state, but the function might not complete before your build function runs. Since the function has not complete dataJsonObject could still be null. What you should do is ensure that your future completes, then only render the widget. You can achieve this by using a future builder. Here is how I would re-write your code:

import 'dart:convert'; //(jsonDecode)

import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; // (loadJson)

class ProverbDisplay extends StatefulWidget {
  final int myId;
  final String myCountry;

  const ProverbDisplay(this.myId, this.myCountry);

  @override
  _ProverbDisplayState createState() => _ProverbDisplayState();
}

class _ProverbDisplayState extends State<ProverbDisplay> {
  Future getJsonProverbFuture = getJsonProverb();

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
        future: getJsonProverbFuture,
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            return Text('Loading...');
          } else {
            return Container(
              color: Colors.blue,
              height: 250,
              child: Row(
                children: [
                  Container(
                    width: 300,
                    child: PageView.builder(itemBuilder: (context, index) {
                      return Text("${snapshot.data}");
                    }),
                  ),
                ],
              ),
            );
          }
        });
  }
}

//Get JSON
Future getJsonProverb() async {
  final String rawJson = await rootBundle.loadString('assets/json/data.json');
  return await jsonDecode(rawJson);
}

More info here about future builder https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html

Mozes Ong
  • 1,204
  • 1
  • 11
  • 20
  • 2
    You should not call the async function in the build method. Create a variable and save the future to the variable, then use the variable in the build method. Otherwise, the method will be called multiple times, because the build function might be called multiple times. – nvoigt Aug 29 '21 at 14:26
  • 1
    I agree, will edit it thanks @nvoigt – Mozes Ong Aug 29 '21 at 15:08