9

I am writing a code in flutter in which I am using an SQFlite database. I want to insert image widget from the assets, and I am getting the name of the image from database.

    @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Single Line diagram"),backgroundColor: Colors.red.shade700,),
      body: SingleChildScrollView(
        scrollDirection: Axis.horizontal,
        child: Align(
          //alignment: Alignment.center,
          child: SingleChildScrollView(
            scrollDirection: Axis.vertical,
            child: Row(
              //crossAxisAlignment: CrossAxisAlignment.center,
              children: imageList(),
            ),
          ),
        )
      ),
    );
  }

The above code calls imageList() for the list of images to display.

List<Widget> imageList(){
    List<Widget> singleLineImages = new List();
    List unit;
    for (int i = 0; i <= widget.unitsList.length-1; i++){
      for (int j = 1; j <= int.parse(widget.unitsList[i].quantity); j++){
        print("${widget.unitsList[i].bulletin}, ${widget.unitsList[i].mountType}, ${widget.unitsList[i].disconnect}");
        getfileName(widget.unitsList[i].bulletin, widget.unitsList[i].mountType, widget.unitsList[i].disconnect);
        //if(fileName != null) {
          singleLineImages.add(
              Image.asset("images/SD_Files_2100/$fileName.jpg", height: 400.0, width: 200.0,));
        //}
      }
    }
    return singleLineImages;
  }

I am getting the filename from getFileName() method which is using the database.

getfileName(String bulletin, String mountType, String disconnect)async {
    fileNameList = await db.getSDfileName(bulletin, disconnect, mountType);
    fileName = fileNameList[0]['FileName'];
    print("filename: $fileName");
  }

Now, after calling the getFileName(), the program is not waiting for the fileName and proceeding further, which takes filename as null. The filename is obtained correctly after the Image.asset code. Is there any way, so that the program waits untill it gets the proper filename?

3
  • see Asynchronous Programming: Futures
    – pskink
    Commented Dec 4, 2018 at 7:49
  • 2
    Use FutureBuilder or call a method from initState that calls the async code and then call setState() when the Future completes to re-build with the new value. There are tons of similar questions on StackOverflow. (very frequently asked question) Commented Dec 4, 2018 at 7:55
  • "Is there any way, so that the program waits untill it gets the proper filename?" No, there is no way to wait for a Future to complete. Dart is single-threaded (unless you launch additional isolates) and that won't allow to block execution because then the Future would never complete because it also runs on the blocked thread. Commented Dec 4, 2018 at 8:55

2 Answers 2

7

Start fetching the list in initState() and call setState when the list is fetched, to do this asynchronously. Below you can find a simplified example of this process. Also note the await statement before get Filename. This makes sure you return to that piece of code after is is done executing.

class ListPage extends StatefulWidget {
  @override
  _ListPageState createState() => _ListPageState();
}

class _ListPageState extends State<ListPage> {
  // This should actually be a List<MyClass> instead of widgets. 
  List<Widget> _list;

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

  Future _fetchList() async {
    List<Widget> singleLineImages = new List();
    List unit;
    for (int i = 0; i <= widget.unitsList.length-1; i++){
      for (int j = 1; j <= int.parse(widget.unitsList[i].quantity); j++){
        print("${widget.unitsList[i].bulletin}, ${widget.unitsList[i].mountType}, ${widget.unitsList[i].disconnect}");
        String fileName = await getfileName(widget.unitsList[i].bulletin, widget.unitsList[i].mountType, widget.unitsList[i].disconnect);
      singleLineImages.add(
          Image.asset("images/SD_Files_2100/$fileName.jpg", height: 400.0, width: 200.0,));
      }
    }

    // call setState here to set the actual list of items and rebuild the widget.
    setState(() {
      _list = singleLineImages;
    });
  }

  @override
  Widget build(BuildContext context) {
    // Build the list, or for example a CircularProcessIndicator if it is null.
  }
}

Sidenote: you are making a lot of calls to the database, which is probably inefficient. Try to get the required data in a single db call. But that is another topic.

0

Keep Future<Widget> _list; field in your class.

Add _list = _fetchList(); in the initState() function. Also note that _fetchList should return Future<Widget> in this case. Use FutureBuilder in your build function.

Not the answer you're looking for? Browse other questions tagged or ask your own question.