Flutter: Exception caught by Streambuilder - android

Hey I am trying to get data of my firestore database to display it in a chart. There are some similar Questions on this topic but they couldnt solve my problem. Following the error causing widget:
Widget _buildBody(context) {
return StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('TopTen').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return LinearProgressIndicator();
} else {
List<Klicks> klicks = snapshot.data.docs
.map(
(documentSnapshot) => Klicks.fromMap(documentSnapshot.data()))
.toList();
return _buildChart(context, klicks);
}
}
);
}
After running my App the LinearProcessIndicator is shown quickly and then the errorpage gets displayed with the following message:
Failed assertion: boolean expression must not be null
The relevant error-causing widget was
StreamBuilder<QuerySnapshot>
If I dont quit the App the errormessage gets build all the time.
I've set up the firestore collection called 'TopTen'. As requested this is the 'Klicks' class
class Klicks{
final int gesamtKlicks;
final String name;
Klicks(this.gesamtKlicks,this.name);
Klicks.fromMap(Map<String,dynamic> map)
:assert(map['gesamtKlicks']=!null),
assert(map['name']=!null),
gesamtKlicks=map['gesamtKlicks'],
name=map['name'];
#override
String toString() => "Record <$gesamtKlicks:$name>";
}
And finally the database:
thanks in advance!

Related

Firestore single document snapshot stream not updating

My Flutter application needs to listen for any changes in a specific Firestore document.
The process is quite simple and is found here in various solutions:
StackOverflow: flutter-firestore-how-to-listen-for-changes-to-one-document
StackOverflow:can-i-listen-to-a-single-document-in-firestore-with-a-streambuilder
StackOverflow:using-stream-building-with-a-specific-firestore-document
StackOverflow: how-to-get-a-specific-firestore-document-with-a-streambuilder
Medium: how-to-get-data-from-firestore-and-show-it-on-flutterbuilder-or-streambuilder-e05
These are all solutions to using a Stream & StreamBuilder and listening for any changes.
Commonly one uses this approach:
Stream<UserModel?> getFirestoreUser(String uid) {
return FirebaseFirestore.instance.collection('users').doc(uid).snapshots().map((event) => event.data()).map((event) => event == null ? null : UserModel.fromJson(event));
}
where:
UserModel has a fromJson(Map<String, dynamic>) factory constructor
and where there exists a users collection with the document ID being uid.
Stream returns a Stream<UserModel?> that can be used later by a Provider.of<UserModel?>(context) or in a StreamBuider<UserModel?>
Problem:
TL;DR - after a Firestore().getCurrentUser(uid) stream is updated (directly, or manually using firestore emulator and changing the document values), the StreamBuilder<UserModel?> below doesn't update.
At all points in app lifecycle (authenticated or not), the stream always returns null (however manually invoking the stream with .first returns the user content, but .last just hangs). See below for more info.
Link to github project.
To get started:
Throw in your own gooogle-services.json file into android/app folder
change all references for com.flutterprojects.myapp to ${your google-services.json package name}
Use local emulator to update firestore changes
More Details:
My issue uses a similar approach, yet the Stream doesn't return anything. My Flutter widget LoggedIn() is used when the FirebaseAuth.instance.currentUser is valid (i.e. not null)
class LoggedIn extends StatelessWidget{
#override
Widget build(BuildContext context) {
// TODO: implement build
return StreamBuilder<UserModel?>(
builder: (context, snapshot) {
print("Checking UserModel from stream provider");
if (snapshot.data == null) {
print("UserModel is null");
return UiLogin();
}
print("UserModel is NOT null");
return UiHome();
},
);
}
}
After a successful authentication, the text Checking UserModel from stream provider is printed to the console, then UserModel is null. At no point does UserModel is NOT null get shown.
After successful authentication (i.e. user registered & document updated), I have a button that I manually invoke the stream and get the first item:
var currentUser = Firestore().getCurrentUser(FirebaseAuth.instance.currentUser!.uid);
var first = await currentUser.first;
print(first);
which returns the UserModel based on the newly added user information.
When running the following code, execution stops on .last, no error, no crash, no app exit, just stops executing.
var currentUser = Firestore().getCurrentUser(FirebaseAuth.instance.currentUser!.uid);
var last = await currentUser.last;
print(last);
BUT
When adding the following, any changes gets updated and printed to the console
Firestore().getCurrentUser(currentUid).listen((data) {
print("Firestore Data Changed");
print("Firestore change value: $data");
});
This means the StreamBuilder<UserModel?> isn't working correctly, as the Stream<UserModel> events do listen() to changes and acknowledge those changes, but the StreamBuilder<UserModel?> changes do not get affected and consistently returns null.
Am I doing something wrong?
Try if (snapshot.hasData) { print("UserModel is null"); return UiLogin(); }
This is working for me. Maybe the connection states are what's missing.
StreamBuilder(
stream: FirebaseFirestore.instance
.collection('users')
.doc(widget.uid)
.collection('contacts')
.doc(widget.client)
.collection('messages')
.orderBy('timestamp', descending: true)
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError)
return Expanded(
child: Center(child: Text('Problem Getting Your Messages')),
);
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('waiting');
case ConnectionState.waiting:
return Center(child: Text('Waiting'));
case ConnectionState.active:
var snap;
print('active');
if (snapshot.data != null) {
snap = snapshot.data;
}
return Expanded(
child: ListView(
...
);
case ConnectionState.done:
print('done');
return Text('Lost Connection');
}
return Text('NOPE');
},
),

Flutter SQLite database , getter 'length' was called on null error, while trying to showing all rows in Database as listview

I recently started using Flutter for app development. I am trying to make a simple notepad app from scratch as part of the learning assignment. can anyone help me where I am making the mistake or if I am missing any fundamental concept? Thanks in advance, below are the details of the issue.
I wrote a database_helper class and a function to show all elements in the database as a list.
//code from Database_Helper.dart
//get the total number of rows in DB.
Future<int> getCount() async {
Database db = await this.database;
List<Map<String, dynamic>> x =
await db.rawQuery('SELECT COUNT (*) from $ideaTable');
int result = Sqflite.firstIntValue(x);
return result;
}
//get total rows in db as <list <map>>
Future<List<Map<String, dynamic>>> getIdeaMapList() async {
Database db = await this.database;
var result = await db.rawQuery('SELECT * FROM $ideaTable ');
return result;
}
//converting list<map> to list<Ideas> // Ideas being defined class.
Future<List<Idea>> getIdeaList() async {
var ideaMapList = await getIdeaMapList(); // Get 'Map List' from database
int count =
ideaMapList.length; // Count the number of map entries in db table
List<Idea> ideaList = List<Idea>();
// For loop to create a 'todo List' from a 'Map List'
for (int i = 0; i < count; i++) {
ideaList.add(Idea.fromMapObject(ideaMapList[i]));
}
return ideaList;
}
}
the database helper object is created in main file and list is shown as vertical Listview using ShowIdea class as shown below.
class _ShowideasState extends State<Showideas> {
DatabaseHelper _databaseHelper = new DatabaseHelper();
List<Idea> listideas;
#override
Widget build(BuildContext context) {
debugPrint('micheal jackson: listideaslength');
if (listideas == null) {
updatelistideas();
}
int j = listideas.length;
debugPrint('micheal jackson: $j listideaslength');
return Container(
child: ListView.builder(
itemCount: listideas.length,
itemBuilder: (BuildContext context, int position) {
return Card(
color: Colors.green[200],
elevation: 2.0,
child: Column(
children: <Widget>[
Text(this.listideas[position].iTitle),
Text(this.listideas[position].iText),
Text(this.listideas[position].date),
],
),
);
}),
);
}
void updatelistideas() async {
listideas = await _databaseHelper.getIdeaList();
int i = listideas.length;
debugPrint('ideaslength: $i listideaslength');
}
}
the following logs
2020-08-23 20:36:51.866 24126-24169/com.example.myprojet01 I/flutter: micheal jackson: listideaslength
2020-08-23 20:36:51.868 24126-24169/com.example.myprojet01 I/flutter: movieTitle: get database list
2020-08-23 20:36:52.358 24126-24169/com.example.myprojet01 I/flutter: idea list length in db: 5
2020-08-23 20:36:52.358 24126-24169/com.example.myprojet01 I/flutter: ideaslength: 5 listideaslength
but the widget is not rendered and shows a red screen with error 'getter length was called on null'.
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building Showideas(dirty, state: _ShowideasState#193ad):
The getter 'length' was called on null.
Receiver: null
Tried calling: length
The relevant error-causing widget was:
Showideas
if the app is hot reloaded without any changes.
The following logs add up and the screen turns white and is overflowed.
2020-08-23 20:36:56.041 24126-24169/com.example.myprojet01 I/flutter: micheal jackson: listideaslength
2020-08-23 20:36:56.041 24126-24169/com.example.myprojet01 I/flutter: micheal jackson: 5 listideaslength
Try the code below :
void updatelistideas() async {
final ideas = await _databaseHelper.getIdeaList();
setState(() {
listideas = ideas;
});
int i = listideas.length;
debugPrint('ideaslength: $i listideaslength');
}
and change this :
itemCount: listideas.length,
to
itemCount: null == listideas ? 0 : listideas.length,

Flutter async memorizer

I am using my own API. I only want to fetch data once when I log into my account. I found AsyncMemorizer.
AsyncMemoizer _memorizer = AsyncMemoizer();
I have 3 future functions and they return Future. Normally without AsyncMemorizer it works fine but in this case, I had an error.
fetchData(Store store) {
return this._memorizer.runOnce(() async {
return await Future.wait([
fCustomer(store),
fList(store),
fCompanies(store)
]);
});
}
#override
Widget build(BuildContext context) {
Store store = StoreProvider.of<AppState>(context);
return FutureBuilder<List<bool>>(
future: this._fetchData(store),
builder: (
context,
AsyncSnapshot<List<bool>> snapshot,
) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
}
if (snapshot.data.every((result) => result == true)) {
return screen();
}
return Text("Sıqıntı");
},
);
}}
error:
The following assertion was thrown building HomeScreen(dirty, dependencies: [StoreProvider<AppState>], state: _HomeScreenState#79c31(tickers: tracking 1 ticker)):
type 'Future<dynamic>' is not a subtype of type 'Future<List<bool>>'
I found a solution about it.
AsyncMemoizer _memorizer = AsyncMemoizer<List<bool>>();
Generic AsyncMemorizer works.

Extracting info from QuerySnapshot variable in flutter app

This code is running fine with futurebuilder and i m getting a listview properly.
But i want to see into the documents n print the details in console. I m not getting any idea about how to do this with QuerySnapshot variable.
Future getP() async {
var firestore = Firestore.instance;
var q = await firestore.collection('place_list').getDocuments();
print(q.documents);
return q.documents;
}
I think I have to call it n wait for the responses then print them, can anyone guide me how to do it?
List<Map<String, dynamic>> list =
q.documents.map((DocumentSnapshot doc){
return doc.data;
}).toList();
print(list);
Though the answer is right the current firebase API has changed drastically now to access QuerySnapshot one can follow the below code.
FirebaseFirestore.instance
.collection('users')
.get()
.then((QuerySnapshot querySnapshot) => {
querySnapshot.docs.forEach((doc) {
print(doc["first_name"]);
});
});
And if you are using async/await then first you need to resolve the AsyncSnapshot and then work on it. If you like:
return FutureBuilder(
future: PropertyService(uid:userId).getUserProperties(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.connectionState == ConnectionState.done) {
snapshot.data.docs.forEach((element) {
Property property = Property.fromJson(element.data());
});
return Text("Demo Text");
}
return LoadingPage();
}
);
taken from url
//But I am not getting all the documents present in my firestore DB collection. The first 10 or so entries are getting printed in the console. //
I think that is standard behavior. If you have one million records it can't print everything in console. To check any particular set of documents you have to filter through where condition in query.
If you have still this problem, I hope this will help you.
This is how I get data from QuerySnapshot:
QuerySnapshot snapshot =
await userCollection.where("uid", isEqualTo: uid).get();
List<Object?> data = snapshot.docs.map((e) {
return e.data();
}).toList();
Map<dynamic, dynamic> userData = data[0] as Map;
print(userData["email"]);
Or you can easily get data by:
QuerySnapshot querySnapshot =
await userCollection.where("uid", isEqualTo: uid).get();
print(querySnapshot.docs[0)['fieldName']);

Flutter - IAP error code 6 with message "the item you were attempting to purchase could not be found"

I am performing in app purchase in my app. I am using Flutter-In-App-Purchase Plugin to implement IAP feature. Following is my code to implement IAP.
class InApp extends StatefulWidget {
#override
_InAppState createState() => _InAppState();
}
class _InAppState extends State<InApp> {
StreamSubscription _purchaseUpdatedSubscription;
StreamSubscription _purchaseErrorSubscription;
StreamSubscription _conectionSubscription;
final List<String> _productLists = Platform.isAndroid
? ["Buy Book"]
: ["Buy Book"];
List<IAPItem> _items = [];
List<PurchasedItem> _purchases = [];
#override
void initState() {
super.initState();
initPlatformState();
}
#override
void dispose() {
if (_conectionSubscription != null) {
_conectionSubscription.cancel();
_conectionSubscription = null;
}
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
// prepare
var result = await FlutterInappPurchase.instance.initConnection;
print('result: $result');
if (!mounted) return;
_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');
});
}
void _requestPurchase(IAPItem item) {
FlutterInappPurchase.instance.requestPurchase(item.productId);
}
Future _getProduct() async {
List<IAPItem> items = await FlutterInappPurchase.instance.getProducts(_productLists);
for (var item in items) {
print('${item.toString()}');
this._items.add(item);
}
setState(() {
this._items = items;
this._purchases = [];
});
_getPurchases();
}
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;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: RaisedButton(
onPressed: () {
_requestPurchase(_items[0]);
},
child: Text("Buy Item"),
),
),
);
}
}
When i click on BuyItem and requestPurchase() method gets called. I gets following error logs and get the error like "the item you were attempting to purchase could not be found"
W/ActivityThread( 8794): handleWindowVisibility: no activity for token
android.os.BinderProxy#572f129 W/ProxyBillingActivity( 8794): Activity
finished with resultCode 0 and billing's responseCode: 6
W/BillingHelper( 8794): Couldn't find purchase lists, trying to find
single data. W/BillingHelper( 8794): Received a bad purchase data.
W/BillingHelper( 8794): Couldn't find single purchase data as well.
E/DoobooUtils( 8794): Error Code : 6 I/flutter ( 8794):
purchase-error: responseCode: 6, debugMessage: , code: E_UNKNOWN,
message: An unknown or unexpected error has occured. Please try again
later.
Please suggest a solution.
Thanks.
I think your in app product will be in the inactive state.
By default, when you add a managed product in the play console it will be in the inactive state. So just visit your in app products in your google play console account and verify that it is active.
Also, make sure that VersionCode and VersionName of the app you are developing/testing should be atleast the version in the google play developer console/play store.
For flutter you can check your versioning in the pubspec.yaml file.
Check your debug package name is equal to your release package name

Categories

Resources