Flutter shared prefernce return NULL - flutter

I have next piece of flutter code, to get shared preference key-value
I do understand why _blueUriInit is always NULL

I assume that you are forgot to provide the value for that key before call to get its value, you need to first assign value to it first:
Future<bool> saveData(String key, dynamic value) async {
final prefs = await SharedPreferences.getInstance();
return prefs.setString(key, value);
}
and call it like this:
void initState() {
saveData('blueUri', 'test');
setState(() {
_blueUriInit = getValue('blueUri');
});
super.initState();
}
now next time you open your app, getValue should return you test.

you can create this function for setting value
static setUserID(String key, String value) async {
final SharedPreferences preferences = await SharedPreferences.getInstance();
preferences.setString(key, value);
}
Use case :
await SharedValue.setUserID("Email", "demo#gmail.com");
And For getting value from shared preference you can use this function
static Future<String?> getUserID(String key) async {
final SharedPreferences preferences = await SharedPreferences.getInstance();
return preferences.getString(key);
}
Use case :
userName = await SharedValue.getUserID("Email");

First you need to setString with key and value (name is key)
Future setValue() async {
final prefs = await SharedPreferences.getInstance();
prefs.setString("name", "Hitarth");
}
getString with key (here i took "name" as key)
Future getValue(String key) async {
final prefs = await SharedPreferences.getInstance();
String value = prefs.getString(key) ?? "NULL";
return value;
}
store in variable callin getValue
void initState() {
setState(() {
_blueUriInit = getValue("name");
});
super.initState();
}

Related

Flutter, how to set and get list of values in shared preferences

I have SharedPreferencesHelper class where I stored simple data that I need.
I came across an issue. I need to store 3-4 strings in the list in shared preferences. How can I do the setter and getter for it?
SharedPreferencesHelper class:
class SharedPreferencesHelper {
static SharedPreferences? _preferences;
Future<void> init() async {
_preferences ??= await SharedPreferences.getInstance();
}
String get username => _preferences?.getString(keyUsername) ?? '';
set username(String value) {
_preferences?.setString(keyUsername, value);
}
// get aliases
List<String>? get aliases => _preferences?.getStringList(keyAliases);
// set aliases
}
You can do this to save list of string:
var pref = await SharedPreferences.getInstance();
pref.setStringList('someList',['1','2','3']);
and get it like this:
var result = pref.getStringList('someList');
if (result != null) {
print('result= $result'); //result= [1, 2, 3]
}
You can write the code like that :
class SharedPreferencesService {
SharedPreferencesServiceImpl(this.preferences);
final SharedPreferences preferences;
/// Static Variables
static const _userId = 'user_id';
#override
Future<String?> get userId async => preferences.getString(_userId);
#override
Future<void> setUserId(String value) async =>
await preferences.setString(_userId, value);
#override
Future<void> clear() async => await preferences.clear();
}
Moreover, you have to inject SharedPreferencesInstance in your getIt (recommended to use)
final getIt = GetIt.instance;
Future<void> setupExternals() async {
final prefs = await SharedPreferences.getInstance();
getIt.registerLazySingleton(() => prefs);
getIt.registerLazySingleton<SharedPreferencesService>(
getIt());
}

Flutter shared preference code optimization suggestion?

I am using the shared_preferences package. https://pub.dev/packages/shared_preferences/example
In my repository class, for each function, I am doing this to get the instance.
SharedPreferences prefs = await SharedPreferences.getInstance();
class AuthenticationRepository {
Future<dynamic> logIn({required String email, required String password}) async {
SharedPreferences prefs = await SharedPreferences.getInstance(); <--------
....
prefs.clear();
prefs.setString('user', encodedUser);
}
Future<String> logOut() async {
SharedPreferences prefs = await SharedPreferences.getInstance(); <---------
prefs.clear();
if(prefs.containsKey('user')){
return 'failed';
}else{
return 'cleared';
}
}
}
I am just wondering if this is initiating a new sharedPreference object or as the function implies, we are only getting the same instance?
Is there a better way to create the instance once, maybe as a class variable like below?
class AuthenticationRepository {
SharedPreferences prefs = await SharedPreferences.getInstance();
Future<dynamic> logIn({required String email, required String password}) async {
....
this.prefs.clear();
prefs.setString('user', encodedUser);
}
Future<String> logOut() async {
this.prefs.clear();
if(prefs.containsKey('user')){
return 'failed';
}else{
return 'cleared';
}
}
}
Please advice, thanks in advance :)
Yes, you can get the same instance. In the shared_preference.dart file, there is a static value _completer. Here is getInstance() function. You can see the if (_completer == null), and it immediately returns a value when the _completer had been initialized.
static Completer<SharedPreferences>? _completer;
...
static Future<SharedPreferences> getInstance() async {
if (_completer == null) {
final completer = Completer<SharedPreferences>();
try {
final Map<String, Object> preferencesMap =
await _getSharedPreferencesMap();
completer.complete(SharedPreferences._(preferencesMap));
} on Exception catch (e) {
// If there's an error, explicitly return the future with an error.
// then set the completer to null so we can retry.
completer.completeError(e);
final Future<SharedPreferences> sharedPrefsFuture = completer.future;
_completer = null;
return sharedPrefsFuture;
}
_completer = completer;
}
return _completer!.future;
}
I think it is a better way to use the getInstance() function not to create another class.

Flutter Null Safe Config Class with shared_preferences

In flutter 1.x, I implemented a Config class using the Flutter shared_preferences package; the code looks like this:
import 'package:shared_preferences/shared_preferences.dart';
class Config {
static final Config _config = Config._internal();
factory Config() => _config;
final accessTokenKey = 'accessToken';
String _accessToken;
SharedPreferences prefs;
Config._internal() {
loadData();
}
void loadData() async {
prefs = await SharedPreferences.getInstance();
_accessToken = prefs.getString(accessTokenKey) ?? '';
}
String get accessToken {
return _accessToken;
}
set accessToken(String accessToken) {
_accessToken = accessToken;
_saveString(accessTokenKey, accessToken);
}
_saveString(String key, String value, {String printValue = ''}) {
String printVal = printValue.length > 0 ? printValue : value;
prefs.setString(key, value);
}
}
I’m creating a new project in Flutter 2.x and trying to use the same code, but due to changes associated with null safety I’m having some difficulty getting the updated code just right.
The updated documentation for the package says to initialize the _prefs object like this:
Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
Then create a local prefs object using:
final SharedPreferences prefs = await _prefs;
This is fine, but I don’t want to have to make every class method that uses shared_preferences async then recreate the variable. At the same time I can’t create it as a class variable without initializing it first. Can someone please show me a cleaner way to do this, or do I just have to redeclare it every time I use it?
Also, how do I initialize the config object in my other classes? In my 1.x code, I would just do this:
final Config config = new Config();
then start accessing the properties of the config object. How do I initialize it with all of the async code in the class now?
Here’s where the updated code is today:
import 'package:shared_preferences/shared_preferences.dart';
import '../models/device.dart';
class Config {
static final Config _config = Config._internal();
factory Config() => _config;
final accessTokenKey = 'accessToken';
String _accessToken = '';
Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
Config._internal() {
print('Config constructor');
loadData();
}
Future<void> loadData() async {
final SharedPreferences prefs = await _prefs;
_accessToken = prefs.getString(accessTokenKey) ?? '';
}
String get accessToken {
return _accessToken;
}
set accessToken(String accessToken) {
_accessToken = accessToken;
_saveString(accessTokenKey, accessToken);
}
_saveString(String key, String value, {String printValue = ''}) {
String printVal = printValue.length > 0 ? printValue : value;
print('Config: _saveString("$key", "$printVal")');
final SharedPreferences prefs = await _prefs;
prefs.setString(key, value);
}
}
You can get instance of SharedPreferences as static field in init method:
static SharedPreferences? _prefs; //or: static late SharedPreferences _prefs;
static init() async {
_prefs = await SharedPreferences.getInstance();
}
And call init() somewhere like in build() method of first widget run, for once.Now you can use _prefs everywhere as you want.
If I want to show you a complete class to use SharedPreferences, it looks like this:
import 'package:shared_preferences/shared_preferences.dart';
class SharedPreferencesRepository {
static SharedPreferences? _prefs;
static init() async {
_prefs = await SharedPreferences.getInstance();
}
static putInteger(String key, int value) {
if (_prefs != null) _prefs!.setInt(key, value);
}
static int getInteger(String key) {
return _prefs == null ? 0 : _prefs!.getInt(key) ?? 0;
}
static putString(String key, String value) {
if (_prefs != null) _prefs!.setString(key, value);
}
static String getString(String key) {
return _prefs == null ? 'DEFAULT_VALUE' : _prefs!.getString(key) ?? "";
}
static putBool(String key, bool value) {
if (_prefs != null) _prefs!.setBool(key, value);
}
static bool getBool(String key) {
return _prefs == null ? false : _prefs!.getBool(key) ?? false;
}
}
I hope this useful for you.
If you need to wait for some async work to finish before getting an instance of a class, consider using a static method (not a factory constructor, since constructors must always return the base type).
You can use late fields to allow them to be non-null before you initialize them:
class Config {
late String _accessToken;
String get accessToken => _accessToken;
Config._(); // private constructor to prevent accidental creation
static Future<Config> create() async {
final config = Config();
final preferences = await SharedPreferences.getInstance();
config._accessToken = await preferences.getString('<your key>');
return config;
}
}
If you want to make sure this is initialized before running your app, you can initialize it in your main() method before you call runApp() to give control to the Flutter framework:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized(); // make sure all plugins loaded etc.
final config = await Config.create();
print(config.accessToken);
runApp(MyApp());
}

How to init state of widget variable with Future string in flutter

I have to initialise the state of widget variable with the value stored in StoredProcedure.
void initState() {
widget.query = fetchMake();
super.initState();
}
Future<String> fetchMake() async{
final prefs = await SharedPreferences.getInstance();
return prefs.getString(key);
query.toString();
}
But the issue is that it cant assign that value to query variable and showing error value to type future string cannot assign to string flutter
How can I do that?
fetchMake is async so you have to put await where you call that method but it will not work because you are calling it in initState.
So You have to assign widget.query variable value in that function only. Moreover, as you get data you have to call setState, so data you receive reflect in ui.
In addition to that you have to check query is null or not where you are using it because when first time build method call it will not have any data.
String query;
void initState() {
fetchMake();
super.initState();
}
fetchMake() async{
final prefs = await SharedPreferences.getInstance();
setState((){
query = prefs.getString(key) ?? 'default';
});
}
You can try:
String query;
void initState() {
super.initState();
fetchMake().then((value) {
setState(() {
query = value;
});
});
}
Future<String> fetchMake() async{
final prefs = await SharedPreferences.getInstance();
return prefs.getString(key);
}
1, You can not set state with widget.query.
2, Create a variable query on state of Widget.
3, fetchMake is a async function => using then to wait result.

Instance of 'Future<String>' instead of showing the value

Iam using flutter and I am trying to get a value from shared_preferences that I had set before, and display it in a text widget. but i get Instance of Future<String> instead of the value. here is my code:
Future<String> getPhone() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final String patientPhone = prefs.getString('patientPhone').toString();
print(patientPhone);
return patientPhone;
}
Future<String> phoneOfPatient = getPhone();
Center(child: Text('${phoneOfPatient}'),))
There is await missing before prefs.getString( and use setState() instead of returning the value. build() can't use await.
String _patientPhone;
Future<void> getPhone() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final String patientPhone = await /*added */ prefs.getString('patientPhone');
print(patientPhone);
setState(() => _patientPhone = patientPhone);
}
build() {
...
Center(child: _patientPhone != null ? Text('${_patientPhone}') : Container(),))
}
If you don't have the option to use await or async you can do the following.
getPhone().then((value){
print(value);
});
and then assign a variable to them. From that, you'll have the result from the value.