notifyListeners() running on a loop - android

Notifylisteners is continuously running on a loop
Future<void> fetchAndSetMeal() async {
final List<Meal> loadedProducts = [];
var data = await DataBaseHelpers.getData();
if (data.documents == null) {
return;
}
List<DocumentSnapshot> list = data.documents;
list.forEach((document) async {
var url = await DataBaseHelpers.getImageUrl(document.documentID);
loadedProducts.insert(
0,
Meal(
id: document.documentID,
category: document.data['category'],
description: document.data['description'],
title: document.data['title'],
price: document.data['price'],
imgUrl: url));
});
await Future.delayed(Duration(milliseconds: 300));
print(loadedProducts[0]);
notifyListeners();
_items = loadedProducts;
}
}
//The print and network call statements are also running twice as opposed to //just once for every call. notifyListeners() is running on a loop;

You got your notifyListeners inside foreach loop. Move it outside

Related

Flutter BloC repeat an event again after dio request time out

I have a problem on my flutter app, when try to load a data from api using dio and this api is private so need to be connected to the same network, so to check everything is fine I tried to connect using mobile data that means dio connection won't success and return timeout, when I call that inside BLoC and use BloCBuilder to build UI depending on state bloc return loadingstate then return errorstate and try to do the event again and fail then repeat this over and over, I just want to avoid this and return error state only and stop listening on that event
void _loadAllSpecialities(
LoadAllSpecialities event, Emitter<DoctorsState> emit) async {
emit(
const DoctorsLoadingState(),
);
emit(const DoctorsLoadingState());
final result = await doctorService.getAllSpeciality(event.jwtToken);
print(result.toString());
//has no error and data loaded
if (result.item1 == null) {
final speicailities = result.item2;
emit(DoctorsSpecialitiesLoaded(specialities: speicailities));
} else {
//has error (error not null)
emit(DoctorErrorState(result.item1!));
}
}```
.
class DoctorService {
final List<DoctorSpeciality> specialities = [];
final options = Options(
responseType: ResponseType.json,
receiveTimeout: 2000,
sendTimeout: 2000,
);
final _dio = Dio();
Future<Tuple<String?, List<DoctorSpeciality>>> getAllSpeciality(
String jwtToken) async {
specialities.clear();
var tuple = Tuple<String?, List<DoctorSpeciality>>(null, []);
try {
final response = await _dio.get<List>(ApiVars.specialitiesEndPoint,
options:
options.copyWith(headers: {"Authorization": "Bearer $jwtToken"}));
if (response.statusCode == 200) {
//has no data
if (response.data == null) {
//set error 1
tuple.setNewValues('No data loaded', []);
//print it
log(tuple.item1 ?? '');
//return tuple with error and empty list
return tuple;
}
//has data then map it into list of specialities
response.data?.forEach((element) {
//convert json to speciality and add it to specialities list
specialities.add(DoctorSpeciality.fromJson(element));
});
//set error to null and list to specialites list
tuple.setNewValues(null, specialities);
return tuple;
} else {
//set error to error with the code and list to empty list
tuple.setNewValues('error occur with code ${response.statusCode}', []);
log(tuple.item1 ?? '');
return tuple;
}
} on DioError catch (error) {
//set error to error message and list to empty list
tuple.setNewValues("doc service ${error.message}", []);
log(tuple.item1 ?? '');
return tuple;
}
}
}
I tried add droppable, sequential and didn't work
on<LoadAllSpecialities>(_loadAllSpecialities, transformer: droppable());
I solved the problem by adding Future before function that called inside the handler function and await it to end as code in below
///constructor called super and pass initial state...
on<DoctorsEvent>(
(event, emit) async {
try {
if (event is LoadAllSpecialities) {
// * load all specialities of doctors from api ...
//add await here
await _loadAllSpecialities(event, emit);
}
} catch (error) {
emit(DoctorErrorState(error.toString()));
}
},
);
}
//add future here
Future<void> _loadAllSpecialities(
LoadAllSpecialities event, Emitter<DoctorsState> emit) async {
emit(
const DoctorsLoadingState(),
);
emit(const DoctorsLoadingState());
final result = await doctorService.getAllSpeciality(event.jwtToken);
//has no error and data loaded
if (result.item1 == null) {
final speicailities = result.item2;
emit(DoctorsSpecialitiesLoaded(specialities: speicailities));
} else {
//has error (error not null)
emit(DoctorErrorState(result.item1!));
}
}

Stream returning null even though EVERY print statement is getting printed

I have a Stream which seems to work perfectly fine: Every print statement you see in the stream is getting printed. Also when calling if(snapshot.hasData) it apparently is true. But still, my stream only returns the following: AsyncSnapshot<List<dynamic>>(ConnectionState.done, [], null, null).
What do I need to change in order to be able to access the Data in my retVal variable?
Stream<List>? roomsListStream() {
try {
List<RoomsListModel> retVal = [];
print("userId: $userId");
var rooms = FirebaseFirestore.instance
.collection("rooms")
.where("users", arrayContains: userId)
.orderBy("latestMessageTime", descending: true)
.snapshots();
print("rooms: $rooms");
rooms.forEach((element) {
element.docs.forEach((element) {
print("element: $element");
var room = element.data();
print("room: $room");
var roomId = room["roomId"];
var otherUserId =
room["users"].firstWhere((element) => element != userId);
var lastMessage = room["latestMessage"];
var lastMessageTime = room["latestMessageTime"];
print("otherUserId: $otherUserId");
getOtherUser(otherUserId).then((value) {
print("value: $value");
var avatar = value["photoUrl"];
var name = value["name"];
retVal.add(RoomsListModel(
roomId: roomId,
otherUserId: otherUserId,
avatar: avatar,
name: name,
lastMessage: lastMessage,
lastMessageTime: lastMessageTime));
});
});
});
return Stream.value(retVal);
} catch (e) {
print("Error: $e");
}
}
Try:
var rooms = await FirebaseFirestore.instance
.collection("rooms")
.where("users", arrayContains: userId)
.orderBy("latestMessageTime", descending: true)
.snapshots();

Flutter String is in Future null

I want to use a string in this function that has the phone number of the device.
I get the phone number with this:
Future<void> initMobilNumberState() async {
if (!await MobileNumber.hasPhonePermission) {
await MobileNumber.requestPhonePermission;
return;
}
String mobileNumber = '';
try {
mobileNumber = await MobileNumber.mobileNumber;
_simCard = await MobileNumber.getSimCards;
} on PlatformException catch (e) {
debugPrint("Failed to get mobile number because of '${e.message}'");
}
if (!mounted) return;
setState(() {
var re = RegExp(r'\+[^]*');
_mobileNumber = mobileNumber.replaceRange(0, 3, ''.replaceAll(re, '+'));
});
}
My problem is that if I want to print _mobileNumber or use it in http.get I get null or a error with "Invalid Arguments"
Future<http.Response> _fetchSampleData() async {
String s = _mobileNumber;
print(s);
return http.get('http://test.php?TestPhone=' + _mobileNumber);
}
Future<void> getDataFromServer() async {
final response = await _fetchSampleData();
if (response.statusCode == 200) {
Map<String, dynamic> data = json.decode(response.body);
_list = data.values.toList();
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
showAlertNoInternet(context);
print('Failed to load data from server');
}
}
Where is my mistake?
The problem is that I want to call the phone number before it has even been fetched. So this always resulted in null. I fixed this by fetching the number when I start the app with all the other data I need.

How to return Future<object> and assign it to just object , flutter

I have a custom class that fetches data from the database, that returns Future<List<Line>>, which lies in line_list.dart files :
Future<List<Line>> fetchingLinesData() async {
List<Line> lineList = [];
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'main.db');
Database database = await openDatabase(path, version: 1);
database.transaction((tnx) async {
dbRef.child('line').once().then((DataSnapshot dataSnapshot) async {
dataSnapshot.value.forEach((key, value) async {
List<Station> inLineStations = [];
for (var i = 0; i < 100; i++) {
if (value["station_$i"] != null) {
List<Map> stations = await tnx.rawQuery("SELECT * FROM Station");
stations.forEach((s) {
if (s['stationName'] == value["station_$i"]) {
Station stationInstance = Station(
key: s['key'],
cityName: s['cityName'],
stationName: s['stationName'],
stationLongitude: s['stationLongitude'],
stationLatitude: s['stationLatitude']);
inLineStations.add(stationInstance);
}
});
}
}
Line lineInstance = Line(
startStation: value['start_station'],
endStation: value['end_station'],
inLineStations: inLineStations,
notes: value['notes'],
price: value['price'],
transportationType: value['transportation_type']);
lineList.add(lineInstance);
});
});
});
return lineList;
}
}
and then in my main.dart widget, I have this :
List<Line> allLines = [];
I want to do something like this :
allLines = LinesList().fetchingLinesData();
But of course, it gives me an error as am trying to assign Future<List<Line>> to List<Line>
how to do it?
You have to await for future to complete.
allLines = await LinesList().fetchingLinesData();
You would just put the code below in a async function make main async and make your code
allLines = await LinesList().fetchingLinesData();

need some processing to do before cloud function returns a promise. But promise is return before the processing

i have a cloud function where i pass an array of numbers and compare those numbers with collection in the firestore . And if the numbers are present than return an array with those numbers. But before comparing those numbers the function return empty value in the promise.
I've tried using async await but the execution sequence remained same.
//sort contact list
export const addMessage= functions.https.onCall(async (data:any, context) => {
const col=admin.firestore().collection("joshua");
var match:[]
match=data.list
var perm1=new Array()
res11.push("454675556")
console.log("above resolve")
for(let val in match){
var inter=await Promise.all([getValues(col,val)])
console.log("inside resolve"+inter)
}
perm1.push("23432")
console.log("just before resolve")
return new Promise((res,rej)=>{
res(perm1)
})
});
//the async function which is suppose to process on every iteration
function getValues(col1:any,val1:any)
{
return new Promise(async(res,rej)=>{
var query= await col1.where('Listed','array-contains',val1)
var value=await query.get()
res(value)
})
.catch(err=>{
console.log(err)
})
}
i want the sequence to be asynchronous where the return value from getValues is waited upon and inside getValues result of query.get is waited upon.
so that at last return only be sent when all process is finished.
I think this is what you are looking for
export const addMessage= functions.https.onCall(async (data:any, context) => {
const col = admin.firestore().collection("joshua");
var match:[]
match = data.list
var perm1 = []
// res11.push("454675556") // ? undefined
for(let val in match){
var inter = await getValues(col,val)
console.log("inside resolve" + inter)
}
perm1.push("23432") // ??
// console.log("just before resolve")
return Promise.resolve(perm1)
});
const getValues = async (col1:any, val1:any) => {
const query = col1.where('Listed','array-contains', val1)
var value = await query.get().then(getAllDocs)
return value
}
const getAllDocs = function(data: any) {
const temp: Array<any> = []
data.forEach(function (doc: any) {
temp.push(doc.data())
})
return temp
}

Categories

Resources