Search code examples
flutterdartsharedpreferencesfutureflutter-futurebuilder

FutureBuilder snapshot data type is not correct


I am using a Flutter FutureBuilder widget and SharedPreferences, to wait for the preferences to be loaded before using them to get the language and pass them to child widgets.

Here is my code:

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:i18n_extension/i18n_widget.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:shared_preferences/shared_preferences.dart';

import 'helpers/color.dart';
import 'pages/home.dart';
import '../constants.dart';

void main() {
  runApp(
    const ProviderScope(
      child: MyApp(),
    ),
  );
}

Future<SharedPreferences> getPrefs() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  return prefs;
}

Locale getLanguageSetting(SharedPreferences prefs) {
  String? lang = prefs.getString('language');
  if (LANGUAGES.contains(lang)) {
    return Locale(lang, '');
  }
  return const Locale('en', '')
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: getPrefs(),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
              return MaterialApp(
      localizationsDelegates: const [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: const [
        Locale('en', ''),
        Locale('jp', ''),
      ],
      home: I18n(
          initialLocale: getLanguageSetting(snapshot.data),
          child: HomeWidget(getPrefs: snapshot.data)), // to force locale to jp
    );
        } else {
          return const Center(
            child: CircularProgressIndicator(),
          );
        }
      }
    );
  }
}

But I have trouble with the type of snapshot.data: both the method and widget I'm passing it to send back a type error The argument type 'Object?' can't be assigned to the parameter type 'SharedPreferences'.

I thought snapshot.data should be of type SharedPreferences according to future: getPrefs(), but it seems it's of type AsyncSnapshot<Object?>.

Why? Should I cast snapshot.data into a SharedPreferences type (I'm not very comfortable with casting)? How can I do that?


Solution

  • Define the type in snapshot as AsyncSnapshot<SharedPreferences> snapshot. Then If you are running a null safe version change the type of sharedPreferences to SharedPreferences? in getLanguageSetting also.

        import 'package:flutter/material.dart';
        import 'package:shared_preferences/shared_preferences.dart';
    
        void main() {
          runApp(MyApp());
        }
    
        Future<SharedPreferences> getPrefs() async {
          SharedPreferences prefs = await SharedPreferences.getInstance();
          return prefs;
        }
    
        class MyApp extends StatelessWidget {
          const MyApp({Key? key}) : super(key: key);
    
          @override
          Widget build(BuildContext context) {
            return FutureBuilder(
                future: getPrefs(),
                builder: (context, AsyncSnapshot<SharedPreferences?> snapshot) {
                  if (snapshot.hasData) {
                    print(snapshot.data.runtimeType);
                    getLanguageSetting(snapshot.data);
                    return MaterialApp(
                        localizationsDelegates: const [],
                        supportedLocales: const [
                          Locale('en', ''),
                          Locale('jp', ''),
                        ],
                        home: Container(
                          color: Colors.red,
                        ));
                  } else {
                    return const Center(
                      child: CircularProgressIndicator(),
                    );
                  }
                });
          }
        }
    
        void getLanguageSetting(SharedPreferences? prefs) {
          print(prefs.runtimeType);
        }