Skip to content

[shared_preferences] cast exception with get/setStringList: type 'List<Object?>' is not a subtype of type 'List?' #152607

Closed
flutter/packages
#7268

Description

@itismejy

Steps to reproduce

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'List<Object?>' is not a subtype of type 'List?' in type cast

Expected results

setStringList is not working properly

Actual results

Should be a List<String>, not List<Object>

Code sample

Code sample
final SharedPreferencesWithCache prefsWithCache =
    await SharedPreferencesWithCache.create(
  cacheOptions: const SharedPreferencesWithCacheOptions(
    // When an allowlist is included, any keys that aren't included cannot be used.
    allowList: <String>{'action'},
  ),
);

await prefsWithCache!.setStringList('action', <String>['Earth', 'Moon', 'Sun']);
                            

Screenshots or Video

Screenshots / Video demonstration

[Upload media here]

Logs

Logs
[Paste your logs here]

Flutter Doctor output

Doctor output
[Paste your output here]

Activity

  1. iapicca commented on Jul 31, 2024

    @iapicca

    works for me

    import 'package:flutter/material.dart';
    import 'package:shared_preferences/shared_preferences.dart';
    
    final class SharedPreferencesKeys {
      static const action = 'action';
    }
    
    void main() async {
      final prefsWithCache = await SharedPreferencesWithCache.create(
        cacheOptions: const SharedPreferencesWithCacheOptions(
          allowList: {SharedPreferencesKeys.action},
        ),
      );
    
      await prefsWithCache.setStringList(
        SharedPreferencesKeys.action,
        const ['Earth', 'Moon', 'Sun'],
      );
    
      final actions =
          prefsWithCache.getStringList(SharedPreferencesKeys.action) ?? [];
    
      runApp(
        MaterialApp(
          home: Material(
            child: Column(
              children: [
                for (final action in actions) Text(action),
              ],
            ),
          ),
        ),
      );
    }
    [!] Flutter (Channel stable, 3.22.3, on macOS 14.5 23F79 darwin-arm64, locale en-US)
        ! Warning: `dart` on your path resolves to /opt/homebrew/Cellar/dart/3.4.4/libexec/bin/dart, which is not inside your current Flutter SDK checkout at
          /Users/francesco/fvm/versions/stable. Consider adding /Users/francesco/fvm/versions/stable/bin to the front of your path.
    [✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    [✓] Xcode - develop for iOS and macOS (Xcode 15.4)
    [✓] Chrome - develop for the web
    [✓] Android Studio (version 2022.3)
    [✓] VS Code (version 1.91.1)
    [✓] Connected device (3 available)
    [✓] Network resources
    name: issue_152607
    description: "A new Flutter project."
    publish_to: 'none'
    version: 1.0.0+1
    
    environment:
      sdk: '>=3.4.4 <4.0.0'
    
    dependencies:
      flutter:
        sdk: flutter
      shared_preferences: ^2.3.0
    
    dev_dependencies:
      flutter_test:
        sdk: flutter
      flutter_lints: ^3.0.0
    
    flutter:
      uses-material-design: true
  2. itismejy commented on Jul 31, 2024

    @itismejy
    Author

    is this required?
    final class SharedPreferencesKeys {
    static const action = 'action';
    }

    The docs says just using the string as the key is fine

  3. iapicca commented on Jul 31, 2024

    @iapicca

    is this required? final class SharedPreferencesKeys { static const action = 'action'; }

    The docs says just using the string as the key is fine

    is not required, this is just me avoiding hard-coding the string 'action' all over the place
    you can delete it and replace SharedPreferencesKeys.action with 'action' if you like it better

    does the code run on your device?

    also, you don't need "!" here

    await prefsWithCache!.setStringList

  4. itismejy commented on Jul 31, 2024

    @itismejy
    Author

    I have a global variable of:
    SharedPreferencesWithCache? prefsWithCache;

    In a separate file outside of main, im doing this:
    await prefsWithCache!.setStringList('ingredients', ['cherry', 'diamond']);

    this is causing this error:
    [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'List<Object?>' is not a subtype of type 'List?' in type cast
    #0 SharedPreferencesWithCache.getStringList (package:shared_preferences/src/shared_preferences_async.dart:310:44)

  5. itismejy commented on Jul 31, 2024

    @itismejy
    Author

    I think it has somethign to do when prefsWithCache is used outside of main? I cant seem to setStringList when its outside of main, it keeps complaining of List<Object?>, no issue when doing setString outside of main

  6. itismejy commented on Jul 31, 2024

    @itismejy
    Author

    eg something like this:

    void main() async {
    await WidgetsFlutterBinding.ensureInitialized();
    prefsWithCache = await SharedPreferencesWithCache.create(
    cacheOptions: const SharedPreferencesWithCacheOptions(),
    );
    // await prefsWithCache!.clear();

    List? savedIngredients = prefsWithCache!.getStringList('ingredients');

    print("ingredients");
    // await prefsWithCache!.setStringList('ingredients', ['cherry', 'diamond']);
    print(savedIngredients);

    runApp(ChangeNotifierProvider(
    create: (context) => IngredientsState()..updateState(savedIngredients ?? []), child: const MainApp()));
    }

    class MainApp extends StatelessWidget {
    const MainApp({super.key});

    @OverRide
    Widget build(BuildContext context) {
    prefsWithCache!.setStringList('ingredients', ['cherry', 'diamond']);
    screenWidth = MediaQuery.of(context).size.width;
    screenWidthRatio = screenWidth / prototypeWidth;
    screenHeight = MediaQuery.of(context).size.height;
    screenHeightRatio = screenHeight / prototypeHeight;

    return MaterialApp(
      navigatorObservers: [routeObserver],
      debugShowCheckedModeBanner: false,
      onGenerateRoute: generateRoute,
    );
    

    }
    }

  7. iapicca commented on Jul 31, 2024

    @iapicca

    I have a global variable of:

    please don't do that,
    if you really really want something similar to a global variable you can use a singleton

    singleton example
    import 'package:flutter/material.dart';
    import 'package:shared_preferences/shared_preferences.dart';
    
    final class SharedPreferencesKeys {
      static const action = 'action';
    }
    
    class SharedPreferencesSingleton {
      SharedPreferencesSingleton._internal();
    
      factory SharedPreferencesSingleton() => _instance;
      static final _instance = SharedPreferencesSingleton._internal();
      SharedPreferencesWithCache? _prefsWithCache;
    
      /// you have to remember to call `initialize()`
      Future<void> initialize({Set<String>? allowList}) async {
        _prefsWithCache ??= await SharedPreferencesWithCache.create(
          cacheOptions: SharedPreferencesWithCacheOptions(
            allowList: allowList,
          ),
        );
      }
    
      /// you have to remember to call `dispose()`
      void dispose() {
        _prefsWithCache = null;
      }
    
      SharedPreferencesWithCache get prefsWithCache =>
          _prefsWithCache ??
          () {
            throw Exception('you forgot to initialize');
          }();
    }
    
    void main() async {
      await SharedPreferencesSingleton().initialize(
        allowList: {SharedPreferencesKeys.action},
      );
    
      await SharedPreferencesSingleton().prefsWithCache.setStringList(
        SharedPreferencesKeys.action,
        const ['Earth', 'Moon', 'Sun'],
      );
    
      runApp(const MyApp());
    }
    
    class MyApp extends StatefulWidget {
      const MyApp({super.key});
    
      @override
      State<MyApp> createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      @override
      void dispose() {
        SharedPreferencesSingleton().dispose();
        super.dispose();
      }
    
      @override
      Widget build(context) => const MaterialApp(home: MyHomePage());
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key});
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(context) {
        final actions = SharedPreferencesSingleton()
                .prefsWithCache
                .getStringList(SharedPreferencesKeys.action) ??
            [];
        return Material(
          child: Column(
            children: [
              for (final action in actions) Text(action),
            ],
          ),
        );
      }
    }

    but what you might actually need is a state management
    I can recommend riverpod.dev

  8. itismejy commented on Jul 31, 2024

    @itismejy
    Author

    id like for my variables to be stored locally, so when user starts app again the data is stored again. and throughout the app the user can write to shared preferences. im already using providers for state management

  9. iapicca commented on Jul 31, 2024

    @iapicca

    I think this is more a discussion on best practices rather than an issue with flutter,
    maybe it's better to close the issue and discuss it on discord

  10. darshankawar commented on Jul 31, 2024

    @darshankawar
    Member

    @itismejy
    Check the plugin example to see if it helps in your case or not.
    Also check if this helps.

  11. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Jul 31, 2024
  12. stuartmorgan-g commented on Jul 31, 2024

    @stuartmorgan-g
    Contributor

    @itismejy Please provide a complete reproducible test case that someone can run to see the issue; so far you've only provided fragments that don't compile in isolation, and the description of the error are too vague to be able to investigate (e.g., this comment only shows one line of code and says it causes an exception, but the line of code is a set call and the exception described can only come from get, so there are clearly missing steps there.)

    Also, please indicate which platform you are running on, as it may be platform-implementation-specific.

  13. stuartmorgan-g commented on Jul 31, 2024

    @stuartmorgan-g
    Contributor

    I think this is more a discussion on best practices rather than an issue with flutter,
    maybe it's better to close the issue and discuss it on discord

    @iapicca Please do not discourage people from reporting exceptions. Whether shared_preferences is the subjectively best tool for the use case, or whether globals are good or bad, is not material to the issue here. If a valid sequence of calls to the shared_preferences API can cause a cast exception, then there's a bug in shared_preferences.

  14. changed the title [-][shared_preferences][/-] [+][shared_preferences] cast exception with get/setStringList: `type 'List<Object?>' is not a subtype of type 'List?'`[/+] on Jul 31, 2024
  15. 4 remaining items

  16. added
    packageflutter/packages repository. See also p: labels.
    P1High-priority issues at the top of the work list
    on Jul 31, 2024
  17. iapicca commented on Jul 31, 2024

    @iapicca

    I have a global variable of: SharedPreferencesWithCache? prefsWithCache;

    In a separate file outside of main, im doing this: await prefsWithCache!.setStringList('ingredients', ['cherry', 'diamond']);

    this is causing this error: [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'List<Object?> > > ' is not a subtype of type 'List?' in type cast #0 SharedPreferencesWithCache.getStringList (package:shared_preferences/src/shared_preferences_async.dart:310:44)
    [...]
    I think it has somethign to do when prefsWithCache is used outside of main? I cant seem to setStringList when its outside of main, it keeps complaining of List<Object?>, no issue when doing setString outside of main

    I think this is more a discussion on best practices rather than an issue with flutter,
    maybe it's better to close the issue and discuss it on discord

    @iapicca Please do not discourage people from reporting exceptions. Whether shared_preferences is the subjectively best tool for the use case, or whether globals are good or bad, is not material to the issue here. If a valid sequence of calls to the shared_preferences API can cause a cast exception, then there's a bug in shared_preferences.

    @stuartmorgan
    my bad I thought the reporter (by his/her words [1, 2]) identified the issue in being caused by the use of the package

  18. itismejy commented on Aug 1, 2024

    @itismejy
    Author

    Thanks guys for your work!

  19. added
    r: fixedIssue is closed as already fixed in a newer version
    on Aug 2, 2024
  20. github-actions commented on Aug 16, 2024

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  21. locked as resolved and limited conversation to collaborators on Aug 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P1High-priority issues at the top of the work listp: shared_preferencesPlugin to read and write Shared Preferencespackageflutter/packages repository. See also p: labels.r: fixedIssue is closed as already fixed in a newer versionteam-ecosystemOwned by Ecosystem teamtriaged-ecosystemTriaged by Ecosystem team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions