I have a simple flutter code to retrieve some data from Firestore. the data is retireved correctly, however passing the data from the future function making the result always null. can you advise how to adapt the code to return the list?
that is the class where the actual query is happening:
class DatabaseManager {
final CollectionReference BusinessProfilesCollection =
FirebaseFirestore.instance.collection("BusinessProfilesCollection");
Future GetBusinessProfilesCollection() async {
List businessprofileslist = [];
try {
await BusinessProfilesCollection.get().then((QuerySnapshot) {
QuerySnapshot.docs.forEach((element) {
businessprofileslist.add(element.data());
print(businessprofileslist[0]);
});
});
} catch (e) {
print(e.toString());
return null;
}
}
}
here is the page where I am calling the function: (however the result is always null)
class _ProfilesListPageState extends State<ProfilesListPage> {
List businessprofileslist = [];
#override
void initState() {
super.initState();
fetchBusinessProfilesList();
}
fetchBusinessProfilesList() async {
dynamic result = await DatabaseManager().GetBusinessProfilesCollection();
print(result.toString());
if (result == null) {
print('enable to retieve');
} else {
print('success');
setState(() {
businessprofileslist = result;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold();
}
}
You're not returning anything from GetBusinessProfilesCollection but null, so the result seems somewhat expected.
I guess you want to do:
class DatabaseManager {
final CollectionReference BusinessProfilesCollection =
FirebaseFirestore.instance.collection("BusinessProfilesCollection");
Future GetBusinessProfilesCollection() async {
List businessprofileslist = [];
try {
var QuerySnapshot = await BusinessProfilesCollection.get();
querySnapshot.docs.forEach((element) {
businessprofileslist.add(element.data());
});
return businessprofileslist;
} catch (e) {
print(e.toString());
return null;
}
}
}
Btw: returning null when the load fails, is just going to lead to a null pointer exception when you then do print(result.toString());. So I recommend not catching the error and just letting it bubble up. With that your code can be simplified to:
class DatabaseManager {
final CollectionReference BusinessProfilesCollection =
FirebaseFirestore.instance.collection("BusinessProfilesCollection");
Future GetBusinessProfilesCollection() async {
var QuerySnapshot = await BusinessProfilesCollection.get();
return querySnapshot.docs.map((element) => element.data());
}
}
You just need to return the list
return businessprofileslist;
CODE :
class DatabaseManager {
final CollectionReference BusinessProfilesCollection =
FirebaseFirestore.instance.collection("BusinessProfilesCollection");
Future GetBusinessProfilesCollection() async {
List businessprofileslist = [];
try {
await BusinessProfilesCollection.get().then((QuerySnapshot) {
QuerySnapshot.docs.forEach((element) {
businessprofileslist.add(element.data());
print(businessprofileslist[0]);
});
// you just need to return the list here after filling it up
return businessprofileslist;
});
} catch (e) {
print(e.toString());
return null;
}
}
}
Code with a little improvement:
class DatabaseManager {
final CollectionReference BusinessProfilesCollection =
FirebaseFirestore.instance.collection("BusinessProfilesCollection");
Future GetBusinessProfilesCollection() async {
await BusinessProfilesCollection.get().then((QuerySnapshot) {
QuerySnapshot.docs.map((doc) => doc.data()).toList();
});
}
}
Try that with calling the function in feching
fetchBusinessProfilesList()
async {
dynamic result ;
await DatabaseManager().GetBusinessProfilesCollection().then((value){
result=value;
print(result.toString());
if (result == null) {
print('enable to retieve');
} else {
print('success');
setState(() {
businessprofileslist = result;
});
}
});
}
Related
I use flutter to retrieve a document from my firestore database. to do this, I create a DocumentSnapshot type variable which will be passed as a parameter to my getClasseName() function to retrieve the documents. Inside my function the document exists, so I assign it to my variable but my variable remains null when I want to use it
this is a snippet of my code
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:ude/model/enseignant.dart';
class DBServices {
static final CollectionReference lyceecol =
FirebaseFirestore.instance.collection('Lycee');
static Future getUser(String? lycee, String? id) async {
try {
final QuerySnapshot<Object?> snapshot = await lyceecol
.doc(lycee)
.collection('Enseignant')
.where('Id', isEqualTo: id)
.get();
final EnseignantM userData = snapshot.docs
.map((QueryDocumentSnapshot<Object?> e) => EnseignantM.fromSnapshot(
e as DocumentSnapshot<Map<String?, dynamic>>))
.single;
return userData;
} catch (e) {
print('ENSEIGNANT NOT FOUND');
print(e);
throw e;
}
}
static Future getClasseName(
String? lycee, String? id, List<String> list) async {
try {
String classeName;
int i = 0;
final snapshot = await lyceecol
.doc(lycee)
.collection('Enseignant')
.doc(id)
.collection('Classes')
.get();
for (var classe in snapshot.docs) {
DocumentReference<Map<String, dynamic>> classeRef =
classe.data()["reference"];
DocumentSnapshot<Map<String, dynamic>>? classRoom;
await DBServices.getClasse(classeRef.path, classRoom);
if (classRoom != null) {
print('CLASSENAME ${classRoom.data()!["Nom"]}');
classeName = classRoom.data()!["Nom"];
list[i] = classeName;
print(list[i]);
i++;
} else {
print('Impossible de charger les classes affilees a cet enseignant');
}
}
} catch (e) {
print(e);
rethrow;
}
}
static Future<void> getClasse(
String? path, DocumentSnapshot<Map<String, dynamic>>? classroom) async {
try {
await FirebaseFirestore.instance.doc(path!).get().then((snapshot) {
if (snapshot.exists) {
classroom = snapshot; //.data()!["Nom"];
} else {
debugPrint("Document not found");
}
});
debugPrint('CLASSROOMMMM: ${classroom!.data()!["Nom"]}');
} catch (e) {
debugPrint('CLASSE Not EXIST');
print(e);
rethrow;
}
}
}
---
/*this is where the problem is*/
static Future getClasseName(
String? lycee, String? id, List<String> list) async {
try {
String classeName;
int i = 0;
final snapshot = await lyceecol
.doc(lycee)
.collection('Enseignant')
.doc(id)
.collection('Classes')
.get();
for (var classe in snapshot.docs) {
DocumentReference<Map<String, dynamic>> classeRef =
classe.data()["reference"];
DocumentSnapshot<Map<String, dynamic>>? classRoom;
await DBServices.getClasse(classeRef.path, classRoom);
if (classRoom != null) {
print('CLASSENAME ${classRoom.data()!["Nom"]}');
classeName = classRoom.data()!["Nom"];
list[i] = classeName;
print(list[i]);
i++;
} else {
print('Impossible de charger les classes affilees a cet enseignant');
}
}
} catch (e) {
print(e);
rethrow;
}
}
static Future<void> getClasse(
String? path, DocumentSnapshot<Map<String, dynamic>>? classroom) async {
try {
await FirebaseFirestore.instance.doc(path!).get().then((snapshot) {
if (snapshot.exists) {
classroom = snapshot; //.data()!["Nom"];
} else {
debugPrint("Document not found");
}
});
debugPrint('CLASSROOMMMM: ${classroom!.data()!["Nom"]}');
} catch (e) {
debugPrint('CLASSE Not EXIST');
print(e);
rethrow;
}
}
I tried not to pass my variable as a parameter and to directly assign the Document returned by the function to it, but it didn't work.
Your help will be invaluable to me
am learning api integration with bloc, these exception is been thrown when data is trying to fetch, for loadingstate i assigned a progressindicator then after that state when trying to get data,these exeption is been thrown ,pls helpenter image description here
as per the console i tried to change the data type to from double to num, still same exception
try {
_emitters.add(emitter);
await handler(event as E, emitter);
} catch (error, stackTrace) {
onError(error, stackTrace);
rethrow;
} finally {
onDone();
}
networkfile.dart
class Repository {
List<FakeStore> collections = [];
Future<List<FakeStore>?> getdata() async {
String url = 'https://fakestoreapi.com/products';
final data = await http.Client().get(Uri.parse(url));
if (data.statusCode != 200) {
return null;
} else {
Iterable values = jsonDecode(data.body);
for (var value in values) {
FakeStore fakeStore = FakeStore.fromJson(value);
collections.add(fakeStore);
}
return collections;
}
}
}
bloc.dart
class FakestoreBloc extends Bloc<FakestoreEvent, FakestoreState> {
final Repository repository;
FakestoreBloc({required this.repository}) : super(FakestoreInitialstate()) {
on<FakestoreEvent>((event, emit) async {
if (event is StorelaodEvent) {
emit(Fakestorelaodingstate());
List<FakeStore>? apiresult = await repository.getdata();
if (apiresult == null) {
emit(FAkestoreErrorstate());
} else {
emit(Fakestoreloadedstate(apiresult: apiresult));
}
}
});
}
}
I working on error handling of api's. i want if api is crashed then it display a message of "Server is down" something like this, in UI.
I created a class where i'm creating methods of api, here in getBooks method if i modify the api url then it is printing this Exception, and i want it in UI. The problem is getBooks return type is List<Book>> so we can't return this Exception, any solution how to do this?
Exception
E/flutter (12924): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Exception
here is my api code
class BooksApi {
static Future<List<Book>> getBooks(String query) async {
try {
final url = Uri.parse(
'https://gist.githubusercontent.com/JohannesMilke/d53fbbe9a1b7e7ca2645db13b995dc6f/raw/eace0e20f86cdde3352b2d92f699b6e9dedd8c70/books.json');
final response = await http.get(url);
if (response.statusCode == 200) {
final List books = json.decode(response.body);
return books.map((json) => Book.fromJson(json)).where((book) {
final titleLower = book.title.toLowerCase();
final authorLower = book.author.toLowerCase();
final searchLower = query.toLowerCase();
return titleLower.contains(searchLower) ||
authorLower.contains(searchLower);
}).toList();
} else {
throw Exception;
}
} catch (e) {
print("e");
print(e);
}
throw Exception;
}
}
and calling it like
Future init() async {
setState(() {
isLoading = true;
});
var books = await BooksApi.getBooks(query); //this
var response = await obj.getProduct();
print(response);
setState(() => this.books = books);
setState(() {
isLoading = false;
});
}
You could handle errors with then and onError :
await BooksApi.getBooks(query).then((books) async {
setState(() => {
this.books = books;
this.isLoading = false;
})
}, onError: (error) {
// do something with error
});
or a simple try-catch (you can write try-catch clauses the same way you would in synchronous code).
See handling errors.
You can also use catchError id you don't use async/await :
BooksApi.getBooks(query).then((books) {
setState(() => {
this.books = books;
this.isLoading = false;
})
}).catchError((error, stackTrace) {
print("error is: $error");
});
See futures error handling.
Try to wrap 'var books = await BooksApi.getBooks(query)' with try and catch.
...
try {
var books = await BooksApi.getBooks(query);
} catch (e) {
// To do for UI
}
...
For api, you need to make something like this:
APIModel{
final int code;
// or a success flag
// final bool success;
final String message;
final List<Book> data;
APIModel({this.code,this.message,this.data});
}
It means, every api have its own code,message,and data filed.
When you request, you can check your code or success:
var response = await request(params);
isLoading = false;
if(response.code == 0){}
// or
if(response.success){
// do what you want
}
else {
Toast.show(response.message);
}
You can use build_runner and json_serializable.
In my Flutter app, I have a function returning Future, but I wanna get result as Stream. Here is the function :
Future<bool> isGpsOn() async {
if (await Geolocator().isLocationServiceEnabled()) {
return true;
} else {
return false;
}
}
How to do that?
Read the manual and check my answer:
Stream<bool> gpsStatusStream() async* {
bool enabled;
while (true) {
try {
bool isEnabled = await Geolocator().isLocationServiceEnabled();
if (enabled != isEnabled) {
enabled = isEnabled;
yield enabled;
}
}
catch (error) {}
await Future.delayed(Duration(seconds: 5));
}
}
gpsStatusStream().listen((enabled) {
print(enabled ? 'enabled' : 'disabled');
});
or create convertor:
Stream futureToStream(fn, defaultValue, Duration duration) async* {
var result;
while (true) {
try {
result = await fn();
}
catch (error) {
result = defaultValue;
}
finally {
yield result;
}
await Future.delayed(duration);
}
}
Future<bool> isGpsOn() async {
return await Geolocator().isLocationServiceEnabled();
}
final gpsStatusStream = futureToStream(isGpsOn, false, Duration(seconds: 5));
gpsStatusStream.listen((enabled) {
print(enabled ? 'enabled' : 'disabled');
});
If you don't want to change the return type of your function, you could make callers convert the Future<T> to a Stream<T> by simply calling asStream() on the returned Future.
I'm trying to implement a renewable subscription in flutter using the flutter_in_app_purchases plugin. When I click on the screen that this is declared in, it goes through the initState() function and then gets to the initPlatformState() and goes through that successfully, but when it gets to the getProducts() function, it's returning an empty item list for the List items = FlutterInappPurchase.instance.getSubscriptions([productID]); call. I've added the monthly subscription in both the App Store Connect and Google Play Store and completed the tax forms. Any help would be appreciated.
List<IAPItem> _items = [];
static const String productID = 'monthly_subscription';
#override
void initState() {
super.initState();
print("IN INIT STATE");
initPlatformState();
}
Future<void> initPlatformState() async {
print("In init platform state");
// prepare
final bool available = await InAppPurchaseConnection.instance.isAvailable();
print(available);
var close = await FlutterInappPurchase.instance.endConnection;
var result = await FlutterInappPurchase.instance.initConnection;
print('result: $result');
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) {
print('In not mounded');
return;
}
// refresh items for android
/*try {
String msg = await FlutterInappPurchase.instance.consumeAllItems;
print('consumeAllItems: $msg');
} catch(e){
print(e.toString());
}*/
await _getProduct();
}
Future<Null> _getProduct() async {
print("In get products");
try {
List<IAPItem> items = await FlutterInappPurchase.instance.getSubscriptions([productID]);
print("Items is: $items");
for (var item in items) {
print('${item.toString()}');
this._items.add(item);
}
setState(() {
this._items = items;
});
} catch(e) {
print(e.toString());
}
}
Here you have a working example from app in production. Disclaimer: I'm not using it anymore but the last time I did it worked fine:
class _InAppState extends State<InApp> {
StreamSubscription _purchaseUpdatedSubscription;
StreamSubscription _purchaseErrorSubscription;
StreamSubscription _conectionSubscription;
final List<String> _productLists = Platform.isAndroid
? [
'subs_premium', 'subs_user'
]
: ['subs_premium', 'subs_boss', 'subscripcion_user'];
String _platformVersion = 'Unknown';
List<IAPItem> _items = [];
List<IAPItem> _subscripions = [];
List<PurchasedItem> _purchases = [];
#override
void initState() {
super.initState();
initPlatformState();
}
#override
void dispose() {
super.dispose();
if (_conectionSubscription != null) {
_conectionSubscription.cancel();
_conectionSubscription = null;
}
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
platformVersion = await FlutterInappPurchase.instance.platformVersion;
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// prepare
var result = await FlutterInappPurchase.instance.initConnection;
print('result: $result');
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
// refresh items for android
try {
String msg = await FlutterInappPurchase.instance.consumeAllItems;
print('consumeAllItems: $msg');
} catch (err) {
print('consumeAllItems error: $err');
}
_conectionSubscription = FlutterInappPurchase.connectionUpdated.listen((connected) {
print('connected: $connected');
});
_purchaseUpdatedSubscription = FlutterInappPurchase.purchaseUpdated.listen((productItem) {
print('purchase-updated: $productItem');
});
_purchaseErrorSubscription = FlutterInappPurchase.purchaseError.listen((purchaseError) {
print('purchase-error: $purchaseError');
});
final List<String> _SKUS = widget.premium ? ['subs_boss']
: ['subs_user'] ;
_getSubscriptions(_SKUS);
}
void _requestPurchase(IAPItem item) {
FlutterInappPurchase.instance.requestPurchase(item.productId);
}
Future _getProduct() async {
print('TEST 1 HERE ${_productLists.length}, ${_productLists.first.toString()}');
List<IAPItem> items = await FlutterInappPurchase.instance.getProducts(_productLists);
print('TEST 2 HERE ${items.length}');
for (var item in items) {
print('${item.toString()}');
this._items.add(item);
}
setState(() {
this._items = items;
this._purchases = [];
});
}
Future _getPurchases() async {
List<PurchasedItem> items =
await FlutterInappPurchase.instance.getAvailablePurchases();
for (var item in items) {
print('${item.toString()}');
this._purchases.add(item);
}
setState(() {
this._items = [];
this._purchases = items;
});
}
Future _getSubscriptions(_SKUS) async {
List<IAPItem> items =
await FlutterInappPurchase.instance.getSubscriptions(_SKUS);
for (var item in items) {
print('${item.toString()}');
this._subscripions.add(item);
}
setState(() {
this._items = [];
this._subscripions = items;
});
}
Future _getPurchaseHistory() async {
List<PurchasedItem> items = await FlutterInappPurchase.instance.getPurchaseHistory();
for (var item in items) {
print('${item.toString()}');
this._purchases.add(item);
}
setState(() {
this._items = [];
this._purchases = items;
});
}