flutterlistdartlocal-storage

List<dynamic>' is not a subtype of type 'Iterable<String> in flutter while fetching data from local storage


I am creating a demo for adding and removing favourite products ID to an obs list and later to save to local storage...

While starting the app, it should fetch all favourite products IDs from storage.

While saving to storage, I am saving a List of String, and here I can't understand how to type cast while reading from storage, as it is showing dynamic... How to convert this dynamic to List of String so that I can assign it to my controller's favourites list which is a List of String.

So, my main query is how to convert to the required datatype while reading from storage.

Like I will save List of int, some time List of ProductModel etc...

class FavouriteController extends GetxController {
  RxList<String> favourites = <String>[].obs;

  @override
  void onInit() {
    // TODO: implement onInit
    super.onInit();
    fetchFavouritesFromStorage();// fetching all ids from storage
  }

  void addFavourite(String id) {
    if (favourites.contains(id)) {
      favourites.remove(id);
    } else {
      favourites.add(id);
    }

    MyLocalStorage.instance().saveData('Favourites', favourites);
  }

  void fetchFavouritesFromStorage() async {
    final data = await MyLocalStorage.instance().readData('Favourites');

    if (data == null) {
      print('Null');
    } else {
      final data = MyLocalStorage.instance().readData('Favourites');
      favourites.assignAll(data); // this line is resulting an error
    }
  }
}

Here is my local storage class. It is taken from a youtuber's code sample:

class MyLocalStorage {
  // static final MyLocalStorage _instance = MyLocalStorage._internal();

  late final GetStorage _storage;
  static MyLocalStorage? _instance;
  MyLocalStorage._internal();

  factory MyLocalStorage.instance() {
    _instance??=MyLocalStorage._internal();
    return _instance!;
  }

  static Future<void> init(String bucketName) async
  {
    await GetStorage.init(bucketName);
    _instance=MyLocalStorage._internal();
    _instance!._storage=GetStorage(bucketName);
  }

  //save data
  Future<void> saveData<T>(String key,T value) async{
    await _storage.write(key, value);
  }

  T? readData<T>(String key) {
    return _storage.read<T>(key);
  }

  Future<void> removeData(String key) async{
    await _storage.remove(key);
  }

  Future<void> clearAll() async{
    await _storage.erase();
  }
}

Solution

  • 2 steps here:

    1. read method of GetStorage and, inherently, readData of MyLocalStorage takes type parameter T to understand which type will be returned from this method. Because of this you can invoke readData like this:
    // data will be of List<dynamic> type
    final data = MyLocalStorage.instance().readData<List>('Favourites');
    
    1. Now, you'll have List<dynamic> type for data which is still not sufficient for you task since you need it to be List<String> You can use this code:
    favourites.assignAll(data.map((e) => e.toString()).toList());
    

    This code will make sure that every element is String, even if it wasn't.