I have a shared preferences class containing all shared preferences, and it is been initialized in main.dart
I can access my stored values from a screen if the data is sent through an action - e.g. button tapped. but I can't access the same values when I visit the same screen from another route/screen without the button that has the stored data.
So, I want a situation where I can check if those shared preferences values exist from my main.dart and load them on any screen without having to go through a particular screen.
Below is my code:
//SharedPreferences class
import 'dart:convert';
import 'dart:core';
import 'package:shared_preferences/shared_preferences.dart';
class SaveInputs {
static late SharedPreferences _preferences;
static Future init() async {
_preferences = await SharedPreferences.getInstance();
}
//the storeList method
static Future storeComList(List<dynamic> comm) async {
final List<String> jsonList = comm.map((item) => jsonEncode(item)).toList();
await _preferences.setStringList('comlist', jsonList);
}
//getting the stored value of list data
static List<dynamic>? getComList() {
final List<String>? jsonList = _preferences.getStringList('comlist');
final List? comm = jsonList == null
? jsonList
: jsonList.map((item) => jsonDecode(item)).toList();
return comm;
}
//storing verified sellers
static Future saveVerifiedSeller(bool vseller) async {
await _preferences.setBool('verified', vseller);
}
//getting the stored value of verified sellers
static bool? fetchVerifiedSeller() => _preferences.getBool('verified');
//Seller List
//storing seller list
static Future storeSellerList(List<dynamic> seller) async {
final List<String> jsonList =
seller.map((item) => jsonEncode(item)).toList();
await _preferences.setStringList('sellist', jsonList);
}
//getting the stored value of seller list
static List<dynamic>? getSellerList() {
final List<String>? jsonList = _preferences.getStringList('sellist');
final List? seller = jsonList == null
? jsonList
: jsonList.map((item) => jsonDecode(item)).toList();
return seller;
}
}
//Main.dart
//import all importable...
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await SaveInputs.init();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
//These are the three things I want to get from shared preferences class
bool isVerified = false;
List isListed = [];
List hasSellers = [];
void readData() async {
setState(() {
isVerified = (SaveInputs.fetchVerifiedSeller() ?? false);
isListed = (SaveInputs.getComList() ?? []);
hasSellers = (SaveInputs.getSellerList() ?? []);
});
}
@override
void initState() {
super.initState();
readData();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: appName,
theme: ThemeData(
primarySwatch: appColor,
),
initialRoute: '/',
routes: {
'/': (context) => SplashScreen(),
'/onboarding': (context) => const Onboarding(),
'/login': (context) => const LoginForm(),
'/dashboard': (context) => const Dashboard(),
'/about_us': (context) => const About(),
'/commodity': (context) => const Commodity(),
},
);
}
}
I can access stored shared preferences if the data is passed via button but I can't see those values when the app loads because it goes from splash screen to the onboarding screen. So I want a situation where as app loads, from main.dart where the routes are, it checks for those stored value that is needed and can be passed unto any of those routes/screens.
CodePudding user response:
I believe you are having a problem because initializing shared preferences is async, as in this line:
_preferences = await SharedPreferences.getInstance();
So what you can do is to make peace with it. In your readData()
function you can have this line (also create _preferences
variable in that class).
_preferences = await SharedPreferences.getInstance();
And then in the build()
function of MyApp
, you can have code like:
if (_preferences == null) return Text('Waiting for preferences to be loaded');
return Text('Preferences is loaded, here is a sample: ${_preferences.getBool('verified')}');
This way you will effectively wait for preferences to load before you use it in your build()
function.
CodePudding user response:
I suggest putting those variables in your SaveInputs
class and initializing them in your init
function.
class SaveInputs {
static late SharedPreferences _preferences;
static bool isVerified = false;
static List isListed = [];
static List hasSellers = [];
static Future init() async {
_preferences = await SharedPreferences.getInstance();
await _readData();
}
static Future<void> _readData() async {
isVerified = fetchVerifiedSeller() ?? false;
isListed = getComList() ?? [];
hasSellers = getSellerList() ?? [];
}
...
}
This way they're fully initialized before MyApp
is built and if needed you can navigate based on those values without having to initialize them in your MyApp
widget. And it could then be stateless.
You could pass any of those values to other screens or access them directly from any page with SaveInputs.isListed
etc...