Access other Class method in Flutter/dart - class

I was working on login with preference. Everything is working fine when I wrote all code in main.dart.
Problem:
When I create separate class on MySharePref then I am getting some error.
MySharePref.dart
import 'package:first_app/UserModel.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SharePrefClass {
void _saveData(UserModel model) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString("Username",model.userName);
await prefs.setString("Password", model.password);
}
Future<UserModel> _getData() async{
SharedPreferences preferences = await SharedPreferences.getInstance();
String username = preferences.getString("Username");
String password = preferences.getString("Password");
UserModel model = UserModel(username,password);
return model;
}
}
I want to access these both functions in main.dart:
_checkLogin() async {
UserModel userModel = new UserModel(
userNameEditText.text , passwordEditText.text);
SharePrefClass mySharedPref = new SharePrefClass();
final UserModel returnModel = mySharedPref._getData() ;
if(returnModel.userName == ""){
print("No data");
}else{
print("else executed");
}
}
I am getting error:

The prefix "_" means private field in dart.
Change the method name _getData() to getData() will let you can access this method in main.dart

Related

This expression has a type of 'void' so its value can't be used - Flutter

import 'package:demo_app/services/api.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AuthProvider extends ChangeNotifier{
bool isAuthenticated = false;
late String token;
late ApiService apiService;
AuthProvider() {
init();
}
Future<void> init() async {
token = await getToken();
if (token.isNotEmpty) {
isAuthenticated = true;
}
apiService = ApiService(token);
notifyListeners();
}
Future<void> register(String name, String email, String password, String passwordConfirm, String deviceName) async{
token = await apiService.register(name, email, password, passwordConfirm, deviceName);
isAuthenticated = true;
setToken();
notifyListeners();
}
Future<void> logIn(String email, String password, String deviceName) async{
token = await apiService.login(email, password, deviceName);
isAuthenticated = true;
setToken();
notifyListeners();
}
Future<void> logOut() async{
token = '';
isAuthenticated = false;
setToken();
notifyListeners();
}
Future<void> setToken() async{
final pref = await SharedPreferences.getInstance();
pref.setString('token', token);
}
Future<void> getToken() async{
final pref = await SharedPreferences.getInstance();
pref.getString('token') ?? '';
}
}
token = await getToken();
gives this error
This expression has a type of 'void' so its value can't be used.
Try checking to see if you're using the correct API; there might be a function or call that returns void you didn't expect. Also check type parameters and variables which might also be void.
Any clue on solving this issue?
Try the following code:
Future<void> init() async {
token = await getToken();
if (token.isNotEmpty) {
isAuthenticated = true;
}
apiService = ApiService(token);
notifyListeners();
}
Future<String> getToken() async {
final pref = await SharedPreferences.getInstance();
final token = pref.getString("token") ?? "";
return token;
}

How to store data in shared preference when retrieve from database firestore in flutter?

In my code at the home page fetch user name from firestore database and that's display nicely in UI. I want pass that name to shared preference function and store there and use that name in another pages also.
Code
home page code ( initstate and send name to saveNameToSharedPreferences() method )
#override
void initState() {
super.initState();
getData();
fetchName();
storeName();
}
void storeName() {
String displayName = '${user?.displayName}';
return displayName.saveNameToSharedPreferences();
}
SharedPreferences code
import 'package:shared_preferences/shared_preferences.dart';
String? _displayName;
String? get displayName => _displayName;
Future saveNameToSharedPreferences() async {
final SharedPreferences sn = await SharedPreferences.getInstance();
await sn.setString('displayName', _displayName!);
}
Future getNameFromSharedPreferences() async {
final SharedPreferences sn = await SharedPreferences.getInstance();
_displayName = sn.getString('displayName');
}
How to solve this ?
You are calling function as an extension. Try to pass parameter instead.
Make the following changes
Future saveNameToSharedPreferences(String displayName) async {
final SharedPreferences sn = await SharedPreferences.getInstance();
await sn.setString('displayName', displayName);
}
And call it as
void storeName() {
String displayName = '${user?.displayName}';
saveNameToSharedPreferences(displayName);
}

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 delete data of shared-preferences from singleton in flutter?

I make one file to shared preferences to store data in it from my app. It's work fine.But now I want to delete data from store as button log-out for user. So if user click button of log-out data will be clear from shared preferences file. How I can do it from different class?
import 'package:shared_preferences/shared_preferences.dart';
class MyPreferences{
static const USER = "user";
static const PASSWORD = "password";
static final MyPreferences instance = MyPreferences._internal();
//Campos a manejar
SharedPreferences _sharedPreferences;
String user = "";
String password = "";
MyPreferences._internal(){
}
factory MyPreferences()=>instance;
Future<SharedPreferences> get preferences async{
if(_sharedPreferences != null){
return _sharedPreferences;
}else{
_sharedPreferences = await SharedPreferences.getInstance();
user = _sharedPreferences.getString(USER);
password = _sharedPreferences.getString(PASSWORD);
return _sharedPreferences;
}
}
Future<bool> commit() async {
await _sharedPreferences.setString(USER, user);
await _sharedPreferences.setString(PASSWORD, password);
}
Future<MyPreferences> init() async{
_sharedPreferences = await preferences;
return this;
}
}
Define your shared preference manager class as a singleton as given,
class SharedPreferenceManager{
static final SharedPreferenceManager _singleton = new SharedPreferenceManager._internal();
factory SharedPreferenceManager() {
return _singleton;
}
SharedPreferenceManager._internal() {
... // initialization logic here
}
... // rest of the class
}
By this, you can create and access the single, reusable instance of that class. You can define a static method in the class which will be accessible from outside. As the static method can have access to only static data members, You should define the sharedPrefernece member variable as static. Here is how you can clear all the data.
static Future<bool> clearSharedPrefs(){
SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.clear();
}
After this, you'll be able to call this method from any class, just as SharedPreferenceManager.clearSharedPrefs().
It's a good practice to follow the singleton pattern for database, network and shared preference related tasks.
Here is the code you should go with.
import 'package:shared_preferences/shared_preferences.dart';
class MyPreferences{
static const USER = "user";
static const PASSWORD = "password";
static final MyPreferences instance = MyPreferences._internal();
static SharedPreferences _sharedPreferences;
String user = "";
String password = "";
MyPreferences._internal(){}
factory MyPreferences()=>instance;
Future<SharedPreferences> get preferences async{
if(_sharedPreferences != null){
return _sharedPreferences;
}else{
_sharedPreferences = await SharedPreferences.getInstance();
user = _sharedPreferences.getString(USER);
password = _sharedPreferences.getString(PASSWORD);
return _sharedPreferences;
}
}
Future<bool> commit() async {
await _sharedPreferences.setString(USER, user);
await _sharedPreferences.setString(PASSWORD, password);
}
Future<MyPreferences> init() async{
_sharedPreferences = await preferences;
return this;
}
static Future<bool> clearPreference() async{
if(_sharedPreferences){
_sharedPreferences.clear();
}
}
}
You can use remove or clear on shared preferences.
SharedPreferences preferences = await SharedPreferences.getInstance();
preferences.clear();
// OR
preferences.remove("MY KEY HERE");