1

I have a list of userIDs and I want to get a value from the database for each user and write it to a new list. But the for loop doesn't wait for the future and throws the error "Unhandled Exception: RangeError (index): Invalid value: Valid value range is empty: 0"

List userIDs = ["gsdgsgsgda32", "gwerszhgda7h", "fsdgz675ehds"];
  Future <dynamic> getList() async {
    List items=[];
    for (var i = 0; i < userIDs.length; i++) {
      items[i] = await getUserItems(userIDs[i]);
    }
    return items;
  }

  Future <String?> getUserItems(String? _userID) async {
    String? userItem=" ";
    final FirebaseApp testApp = Firebase.app();
    final FirebaseDatabase database = FirebaseDatabase.instanceFor(app: testApp);
    database.ref().child('users').child(_userID!).once().then((pdata) {
      userItem = pdata.snapshot.child('item').value as String?;
      });
    return userItem;
  }
Bernhard
  • 188
  • 10

3 Answers3

2

This is not problem with future. List items is empty so when you call items[0] = 3; there is no items[0] and you get RangeError. Proper way to add element to list is call items.add(3)

So your code should look like this:

List userIDs = ["gsdgsgsgda32", "gwerszhgda7h", "fsdgz675ehds"];
  Future <dynamic> getList() async {
    List items=[];
    for (var i = 0; i < userIDs.length; i++) {
      final item = await getUserItems(userIDs[i]);
      items.add(item); 
    }
    return items;
  }

  Future <String?> getUserItems(String? _userID) async {
    String? userItem=" ";
    final FirebaseApp testApp = Firebase.app();
    final FirebaseDatabase database = FirebaseDatabase.instanceFor(app: testApp);
    database.ref().child('users').child(_userID!).once().then((pdata) {
      userItem = pdata.snapshot.child('item').value as String?;
      });
    return userItem;
  }
Corvus Albus
  • 156
  • 4
0

By using .then you are telling dart to continue running and come back when the Future completes. Instead you should use await inside getUserItems.

You have to fiddle around a bit but here's a suggestion to start with:

Future <String?> getUserItems(String? _userID) async {
    String? userItem=" ";
    final FirebaseApp testApp = Firebase.app();
    final FirebaseDatabase database = FirebaseDatabase.instanceFor(app: testApp);
    userItem = (await database.ref().child('users').child(_userID!).once()).snapshot.child('item').value as String?
    return userItem;
  }

Also using String? for userItem and setting it to " " is a bit of an anti pattern. Since you allow it to be nullable i'd suggest having it as null writing your logic around that.

Hampus
  • 276
  • 2
  • 8
-1

Try to use it like this

 Future <dynamic> getList() async {
        List items=[];
        userIDs.forEach((item) async {
          items.add(await getUserItems(item));
        });
        return items;
      }
Maqsood
  • 807
  • 3
  • 14