0

This how i declare my list

  List<String> distance = [];

and here is my ListView builder

   return ListView.builder(
        itemCount: widget.stores.length,
        shrinkWrap: true,
        scrollDirection: Axis.vertical,
        itemBuilder: (BuildContext context, int index) {
          if (widget.latitude == 0.0) {
          } else {
            calculateDistance(widget.stores[index].storeLatitude,
                widget.stores[index].storeLongitude, index);
          }
          return GestureDetector(
            child: Card(
              child: Container(
                width: MediaQuery.of(context).size.width * 0.50,
                child: ListTile(
                  title: Text(
                    widget.stores[index].storeName,
                    style: TextStyle(fontSize: 18),
                  ),
                  subtitle: Text(
                    widget.stores[index].storeAddress,
                  ),
                  trailing: (distance[index].isEmpty) ? Text("") : Text(distance[index]),
                ),
              ),
            ),
          );
        });

i'am adding distance inside the setState()

here is the function to add value for distance

     calculateDistance(widget.stores[index].storeLatitude,
                    widget.stores[index].storeLongitude, index);

-------------
  Future calculateDistance(String storeLatitude, String storeLongitude) async {
      final list =  (await Geolocator().distanceBetween(widget.latitude, widget.longitude,double.parse(storeLatitude), double.parse(storeLongitude)));
      if (list != null) {
        setState(() {
          distance.add((list / 1000).toStringAsFixed(1));
        });
      }
    }

so when it is empty, it is throwing this error

I/flutter (22854): Another exception was thrown: RangeError (index): Invalid value: Valid value range is empty: 0 I/flutter (22854): Another exception was thrown: RangeError (index): Invalid value: Valid value range is empty: 1

how can i fix it ?

here is my full script https://gist.github.com/bobykurniawan11/ef711e5121be303e8102a6ab4871435f

7
  • widget.stores and distance must always be the same size, if calculateDistance has a list that is empty the value is not added to the distance array, therefore widget.stores could have more than distance and it will crash. trailing: (distance[index].isEmpty) ? Text("") : Text(distance[index]), should rather be something like distance.length > index ? Text(distance[index]) : Text('') Commented Jul 23, 2019 at 8:07
  • But your logic is flawed for example supposed I have widget.stores with values A,B,C (i.e length 3) and then distance is calculated for A and C and not for B (ie distance length 2). Then it will crash, and if you add the code I suggested above it wont crash. BUT B at position distance[1] will have the distance value for C, and will have the distance value distance[2] = index out of bounds. (Range Error) Commented Jul 23, 2019 at 8:10
  • @Jason distance is empty at the start. I just want put the result of the calculateDistance to it Commented Jul 23, 2019 at 8:16
  • In the initState set distance to the same size as widget.stores, initialise each value as an empty string. Then populate distance as needed by setting the value in the array. There are more issues with your code, for example setting the state while painting the screen and firing off an async method. But that's another issue. Commented Jul 23, 2019 at 8:19
  • @MyNamels is it working? Commented Jul 23, 2019 at 8:38

2 Answers 2

1

stores is empty

use initState. initState call store data reading method

Sign up to request clarification or add additional context in comments.

3 Comments

like void initState() { distance = []; } ?, if like that, i already did that
for example code@override void initState() { super.initState(); // Call the getJSONData() method when the app initializes this.getJSONData(); } this.getJSONData() is get array method
well, distance is a result for some function. So it is null / empty at the start
0

@MyNamels, please try the following:

Use a state-full widget, in the initState, initialise distance to be the same size as your widget.store. i.e.

@override
initState() {
  super.initState();
  if (widget.store != null) {
     widget.store.forEach((f) => distance.add(''));
  }
}

Then in your calculateDistance set the value at that position i.e.

setState(() {
     distance[index] = (list / 1000).toStringAsFixed(1);
});

The code above should work, and not cause the RangeError(index)

However, calling the calculateDistance during the build is not correct, as the widget could be repainted a lot, and each repaint will call the calculateDistance. Each set state will cause the build to fire again, you can check this by adding a print to the calculate distance, build will re-trigger the calculateDistance and thus an infinite loop. Rather calculate the distance in the initState or pass the complete calculated data to the widget.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.