0

So Here's the code. The error is when calling loadSounds function from outside the class returns an empty list. But when loadSounds is called from loadcategories it works fine and returns a list containing instances of Sound. Even priniting the sounds variable in the loadSounds function prints an empty list.

class AudioRepository {
  List<Category> categories = <Category>[];
  List<Sound> sounds = <Sound>[];

  Future<String> _loadCategoriesAsset() async =>
      await rootBundle.loadString(Assets.soundsJson);

  Future<List<Category>> loadCategories() async {
    if (categories.isNotEmpty) {
      return categories;
    }

    String jsonString = await _loadCategoriesAsset();
    categories.clear();
    categories.addAll(categoryFromJson(jsonString));
    categories.map((c) => sounds.addAll(c.sounds)).toList();
  
    loadSounds('1');
    return categories;
  }

  Future<List<Sound>> loadSounds(String categoryId) async {
    print(sounds);
    return sounds
        .where((sound) => sound.id.substring(0, 1) == categoryId)
        .toList();
  }
}

Output when called from loadCategories is as follows:

[Instance of 'Sound', Instance of 'Sound', Instance of 'Sound', Instance of 'Sound', Instance of 'Sound', Instance of 'Sound']

I'm accessing it outside the class as follows:

final _sounds = await repository.loadSounds(event.categoryId);

Output when called from outside or printing from loadSounds function is as follows:

[]

So what's the problem here. I'm not able to figure out why the loadSounds fuction work when called from loadCategories inside the class and not otherwise in any way.

Shivam Singh
  • 87
  • 2
  • 11

3 Answers3

0

use provider and ChangeNotifier is the best way. your code will be like this

class AudioRepository extends ChangeNotifier {
  List<Category> categories = <Category>[];
  List<Sound> sounds = <Sound>[];

  Future<String> _loadCategoriesAsset() async =>
      await rootBundle.loadString(Assets.soundsJson);

  Future<List<Category>> loadCategories() async {
    if (categories.isNotEmpty) {
      return categories;
    }

    String jsonString = await _loadCategoriesAsset();
    categories.clear();
    categories.addAll(categoryFromJson(jsonString));
    categories.map((c) => sounds.addAll(c.sounds)).toList();

    //notify listeners
    notifyListeners();
    ////
    loadSounds('1');
    return categories;
  }

  Future<List<Sound>> loadSounds(String categoryId) async {
    print(sounds);
    return sounds
        .where((sound) => sound.id.substring(0, 1) == categoryId)
        .toList();
  }
}

to retrieve data from outside, the following code should be placed in Build() methode.

final _arp = Provider.of<AudioRepository>(context, listen: true);

print(_arp._sounds);
bara batta
  • 1,002
  • 8
  • 8
  • I'm using bloc as state management. Can you please provide an alternative in bloc. How to do this? – Shivam Singh Feb 22 '21 at 09:05
  • In presentation layer I'm using BlocBuilder and on SoundsLoaded state I'm using state.sounds to get the list. So on calling right from the BlocBuilder won't provide me with the updated sound list? – Shivam Singh Feb 22 '21 at 09:45
0

If you don't call repository.loadCategories() before calling loadSounds(), you won't have anything in your sounds variable since you are assigning values only in your loadCateogries() function.

Is your repository variable a singleton and did you call loadCategories on it?

Also, I would not write this line like this :

categories.map((c) => sounds.addAll(c.sounds)).toList();

The toList() method is not really usefull and the map function should be used more to convert something (a String to Int mapping for instance).

I would use :

categories.forEach((c)=> sounds.addAll(c.sounds));
leb1755
  • 1,386
  • 2
  • 14
  • 29
  • ok i will change that line. And I'm using get it for injecting services. In that i have registered AudioRepository as factory. – Shivam Singh Feb 22 '21 at 09:14
  • I changed the line as you stated above and now even the loadCategories function is providing an empty list on calling loadSounds. .tolist() is correct. – Shivam Singh Feb 22 '21 at 09:17
  • I don't believe that the problem is related to the .map or .forEach way. Try calling your loadCategories() function before the loadSounds function (using await on each). Also, try using directly the '1' parameter for the loadSounds function to be sure it's not related to the params you give to loadSounds() – leb1755 Feb 22 '21 at 09:21
  • As I said I'm using bloc. So in the main file itself I have done : BlocProvider( create: (context) => getIt()..add(GetCategories()), ), which calls loadCategories function and pass the result to loaded state. – Shivam Singh Feb 22 '21 at 09:27
  • After getting the categories I'm calling the loadSounds function using another bloc using the category.id param. So in any way I'm not calling it before loadCategories. The error have to be in the way I have written the above repository file. – Shivam Singh Feb 22 '21 at 09:31
  • I am pretty sure there are no problems with your AudioRepository class. I don't know much about GetIt but showing code for you CategoriesBloc and GetCategories method may help. Try to make it work without Bloc and GetIt : if the problem is really in the AudioRepository class, you will have it without Bloc and without GetIt. – leb1755 Feb 22 '21 at 09:45
  • Thank you for your suggestion @leb1755. I tried making an instance of AudioRepository in main method and executed the respected methods and it ran correctly. So now I'm assuming I made some mistake in the Bloc or getIt file. Btw thanks for helping. – Shivam Singh Feb 22 '21 at 16:21
  • 1
    I ran the code without using getIt and It worked correctly. I got the problem I registered AudioRepository as a factory but it should have been singleton. So yeah now it works correctly. I missed it above when you asked about singleton. Thank You. – Shivam Singh Feb 22 '21 at 17:38
0

It may be an error in the where clause. Because the condition isn't correct. try this:

return sounds
        .where((sound) => sound.id[0] == categoryId)
        .toList();
Preet Shah
  • 792
  • 5
  • 12
  • No it's correct //sound id = 101, 1 is category id . So using the substring method I'm accessing the first number of the sound Id. then it will provide me with the sounds of that category. – Shivam Singh Feb 22 '21 at 09:48
  • If the where clause was wrong I would not be getting the sound list from anywhere. But when loadSounds called from loadCategories providing the category id it works correctly. But not working from outside the class. – Shivam Singh Feb 22 '21 at 09:50
  • I have made a change, please try that. – Preet Shah Feb 22 '21 at 10:09
  • Ok. So, I think that the problem is you're calling it outside the class. Can you do the following? run `loadCategories()` then run `loadSounds('1')` – Preet Shah Feb 22 '21 at 10:25
  • If this works, then all you need to do is use a state manager. Maybe, Provider or Bloc or MobX. – Preet Shah Feb 22 '21 at 10:58