SharedPreference returning null flutter - flutter

I want to render something from Shared Preferences.
Here is my code :
return FutureBuilder<ChildModel>(
future: sharedPreference.getData(),
builder: (context, snapshot) {
print("SNAPSHOT" + snapshot.data.toString());
if (snapshot.hasData &&
snapshot.data != null) {
return _render(snapshot,context);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
} else {
return Text('Select Vehicle');
}
},
);
My SharedPreferece:
Future<ChildModel> getData() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
ChildModel singleObject ;
List<ChildModel> userVehicleList = [];
getSelectedVehicleID().then((onValue){
if(onValue!=null){
if (prefs.get(_kUserVehicles) != null) {
final List parsedList = json.decode(prefs.get(_kUserVehicles));
userVehicleList = parsedList.map<ChildModel>((val) => ChildModel.fromJson(val)).toList();
}
for (int i = 0; i < userVehicleList.length; i++) {
if (userVehicleList[i].id == onValue) {
singleObject = userVehicleList[i];
}
}
}
});
return singleObject ?? null;
}
The problem is singleObject = userVehicleList[i] is executed but doesnt return anything.
Always snapshot.data is null in Future Builder.
I want to return that singleObject that I found in that loop.
Can Anyone please help me with this ???

You are not awaiting for future to finish before returning value.
So
return singleObject ?? null;
will execute before
getSelectedVehicleID()
What you need is
int _selectedVehicleId = await getSelectedVehicleID();
And then continue getting anything from shared preferences and returning that.
Hope that will help :)

Related

Firestore Image Reference returning error, even though image exists

I have a Wrapper for my Signup flow, in order to show the right screen, depending on if the user did finish the corresponding signup step. Unfortunately, it does not work properly: Even though the image exists in the "userImages" folder for the corresponding user id, my userImageExists variable is returning "false". Does anybody know what is wrong with my code?
class Wrapper extends StatelessWidget {
static String id = 'wrapper';
#override
Widget build(BuildContext context) {
final user = Provider.of<User?>(context);
if (user == null) {
return SignupScreen();
} else {
return FutureBuilder(
future: _checkUserData(user),
builder: (context, snapshot) {
if (snapshot.hasData) {
switch (snapshot.data) {
case UserDataStatus.imageNotUploaded:
return ImageUploadScreen();
case UserDataStatus.verificationImageNotUploaded:
return SignupVerificationScreen();
case UserDataStatus.interestsNotPopulated:
return InterestsScreen();
default:
return LoggedInScreenWrapper();
}
} else {
return Container(
color: Colors.white,
child: Center(child: CircularProgressIndicator()));
}
},
);
}
}
Future<UserDataStatus> _checkUserData(User user) async {
final userImageRef =
FirebaseStorage.instance.ref().child('userImages').child(user.uid);
final verificationImageRef = FirebaseStorage.instance
.ref()
.child('userImages')
.child(user.uid)
.child('verification');
final userDoc =
FirebaseFirestore.instance.collection('users').doc(user.uid);
final userImageExists = await userImageRef
.getData(1)
.then((value) => true, onError: (error) => false);
final verificationImageExists = await verificationImageRef
.getData(1)
.then((value) => true, onError: (error) => false);
final interestsExist = await userDoc
.get()
.then((value) => value['interests'] != null, onError: (error) => false);
print("userImageExists: $userImageExists");
print("verificationImageExists: $verificationImageExists");
print("interestsExist: $interestsExist");
if (!userImageExists) {
return UserDataStatus.imageNotUploaded;
} else if (!verificationImageExists) {
return UserDataStatus.verificationImageNotUploaded;
} else if (!interestsExist) {
return UserDataStatus.interestsNotPopulated;
} else {
return UserDataStatus.allDataPresent;
}
}
}
enum UserDataStatus {
imageNotUploaded,
verificationImageNotUploaded,
interestsNotPopulated,
allDataPresent,
}

Flutter dart async await not working as expected

I am trying to check the internet connection of the mobile device. I am using below code to check the connectivity.
import 'package:flutter/material.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
class RedirectPage extends StatelessWidget {
final int? status;
#override
Widget build(BuildContext context) {
bool? isDeviceConnected;
() async {
print("a");
print(123);
isDeviceConnected = await checkConnection();
print(888);
};
if (isDeviceConnected != null && isDeviceConnected == false) {
return AppNetworkConnectivityHome();
} else{
return HomePage();
}
}
}
print(isDeviceConnected); //giving null for the first time and true or false on the second time.
Future<bool?> checkConnection() async {
bool a = false;
a = await InternetConnectionChecker().hasConnection;
print(a);
return a;
}
how to force wait for the await function to complete
You'd have to await the method call. You've currently defined it as an anonymous function, so depending on where and how you execute it there will be some differences. But it will work if you instead do something like this:
Future<bool?> myMethod() async {
return await InternetConnectionChecker().hasConnection;
}
...
print(await myMethod());
You can't call async function in build method, you need to use FutureBuilder like this:
return FutureBuilder<bool>(
future: checkConnection(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading....');
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
bool data = snapshot.data ?? true;
if (!data) {
return AppNetworkConnectivityHome();
} else{
return HomePage();
}
}
}
},
)

FutureBuilder doesnt work when used with SharedPreferences

I'm getting a type 'Future<dynamic>' is not a subtype of type 'Future<String>'
I am simply trying to use a FutureBuilder in conjunction with SharedPreferences to return a string that I have previously stored using SharedPreferences.
Flutter : 'Future <dynamic>' is not a subtype of type bool
This stack overflow answer is doing the exact same thing as what I'm doing yet I have an error?
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: getRoleFuture(),
builder: (context, snapshot) {
if(snapshot.data == false) {
return Text("No data");
}
else {
return Text(snapshot.data);
}
}
);
}
getRoleFuture() async {
var sp = await SharedPreferences.getInstance();
return sp.getString("role");
}
The reason is that you used snapshot.data as bool in this line
if(snapshot.data == false) {
return Text("No data");
}
where as you set the Future return type as string
maybe if you do this:
if(snapshot.data == null || snapshot.data == '') {
return Text("No data");
}
else {
return Text(snapshot.data);
}
Check the snapshot with hasData.
if(snapshot.hasData == false)
Gives the return type.
Future<String> getRoleFuture() async {
var sp = await SharedPreferences.getInstance();
return sp.getString("role");
}
In you FutureBuilder future pass a refrence to your function:
future: getRoleFuture, (without the parentheses)
so your code should be something like this:
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: getRoleFuture,
builder: (context, snapshot) {
if(!snapshot.hasData) {
return Text("No data");
}
else {
return Text(snapshot.data);
}
}
);
}
Future<String> getRoleFuture() async {
var sp = await SharedPreferences.getInstance();
return sp.getString("role");
}
We don't use the parentheses in that code because we don't want the function to be called at the point where that code is encountered. Instead, we want to pass a reference to our function into the future.

Can not convert Future data to exact data

I am using Future to return some information from Firebase database that return Future .Now i wanted to convert bool.Here i am faceting null .But into the then function i found my value but when i return it its remain null.
Future<bool> _isfav(String post_key) async {
bool _is_fav;
await FirebaseDatabase.instance
.reference()
.child(Common.user)
.child(Common.number)
.child("favourite")
.child(post_key)
.once()
.then((v) {
print(v.value);
if (v.value != null) {
_is_fav = true;
} else {
_is_fav= false;
}
}).catchError((err) => print(err));
return _is_fav; }
This code perfectly fine .But now
bool read_fav(String index) {
bool data;
_isfav(index).then((v){
data= v;
print(data); /// printing data
});
print(data); //printing null
return data; //returning null }
When i print data into the then function its show my data but when i return it its return null.
i wanted calling the function from here
child: Icon(
Icons.favorite,
color:read_fav(_key[index])!=null && read_fav(_key[index]) == true
? Colors.blue
: Colors.black,
)),
Just follow the code like,
Future<bool> _isfav(String post_key) async {
bool _is_fav;
var snapData = await FirebaseDatabase.instance
.reference()
.child(Common.user)
.child(Common.number)
.child("favourite")
.child(post_key)
.once();
if (v.value != null) {
_is_fav = true;
} else {
_is_fav = false;
}
return _is_fav;
}
Future<bool> read_fav(String index) async{
bool data=false;
data=await _isfav(index);
return data;
}
Also, read_fav will be a future method. because it depends on _isFav() return value which will be predicted in future.
bool isReadFav=await read_fav(index);
Just refer dart await and then concepts at Here
You're all set.

How to return Future List from DataSnapshot

I want to return a Future List from Firebase Database snapshot and this is my code but I cant get it work properly:
Future<List<CocheDetailItem>> getCoches(ids) async {
List<CocheDetailItem> coches = [];
final dbRef = FirebaseDatabase.instance.reference().child('17082019');
for (var i = 0; i < ids.length; i++) {
var id = ids[i];
dbRef.child(id).once().then((DataSnapshot snapshot) {
if (snapshot.value != null) {
Map<dynamic, dynamic> jsres = snapshot.value;
CocheDetailItem coche = CocheDetailItem.fromJson(jsres);
coches.add(coche);
}
});
print('here is i ${ids[i]} ');
}
return coches;
}
The return I get is empty Area. Can anyone help me with this, please?
Note, dbRef.child(id).once(); is a async function, so you must wait it ends to get your data. Use await keyword to do it.
Future<List<CocheDetailItem>> getCoches(ids) async {
List<CocheDetailItem> coches = [];
final dbRef = FirebaseDatabase.instance.reference().child('17082019');
for (var i = 0; i < ids.length; i++) {
var id = ids[i];
var dataSnapshot = await dbRef.child(id).once();
if (dataSnapshot.value != null) {
Map<dynamic, dynamic> jsres = dataSnapshot.value;
CocheDetailItem coche = CocheDetailItem.fromJson(jsres);
coches.add(coche);
}
print('here is i ${ids[i]} ');
}
return coches;
}
well.. I don't use firebase but I send a request to my database with this (you have to use async and await)
Future<List<PlaceModel>> getPlaces(String ciudad, String tipo) async {
Uri request = Uri.http('domain.com', '/getPlaces/$ciudad/$tipo');
ResponseModel response = ResponseModel.fromJsonMap(json.decode((await http.get(request)).body));
List<PlaceModel> items = [];
if(response.res) {
if(response.value != null) {
for(var item in response.value) {
final place = PlaceModel.fromJsonMap(item);
items.add(place);
}
}
}
print("Places Loaded: ${items.length}");
return items;
}
I use my ResponseModel to convert the json answer in an object.
Then I show it with the future builder:
class PlacesListPage extends StatelessWidget{
final _selectedLocation, _selectedList;
PlacesListPage(this._selectedLocation, this._selectedList);
final _provider = PlaceProvider();
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8.0),
child: FutureBuilder(
future: _provider.getPlaces(_selectedLocation, _selectedList), // async request to database
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) { // check when your request is done
if(snapshot.data.length != 0) { // check if any data has been downloaded
return ListView.builder( // build a listview of any widget with snapshot data
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
// i just return containers but you can use any custom widget, it's like a forEach and use the index var
return Container(
child: Text(snapshot.data[index]),
);
},
);
} else {
// If you don't have anything in your response shows a message
return Text('No data');
}
} else {
// shows a charge indicator while the request is made
return Center(
child: CircularProgressIndicator(),
);
}
},
),
);
}
}