Integrating multiple Firebase projects in one Flutter app causes app to crash - android

Background:
I am trying to develop a flutter app that connects with 3 different Firebase projects. I followed the instructions on FlutterFire, specifically on FlutterFire Overview and Core | FlutterFire and initialized 3 firebase projects apps inside App.
Note: I have use to 3 different Firebase projects for legality reasons and I cannot use flavors. Also, the app uses shared preferences to store data locally.
Problem:
When I start the emulator and run the app everything seems to work fine. The app starts, connects to all three firebase projects and does everything I want it to. However, now if I try to re-run the app (i.e. stop the app and then press the green arrow to restart it), the app crashes with the error message:
D/AndroidRuntime(16200): Shutting down VM
E/AndroidRuntime(16200): FATAL EXCEPTION: main
E/AndroidRuntime(16200): Process: com.example.flutter_app, PID: 16200
E/AndroidRuntime(16200): java.lang.RuntimeException: Internal error in Cloud Firestore (22.0.1).
E/AndroidRuntime(16200): at com.google.firebase.firestore.util.AsyncQueue.lambda$panic$3(AsyncQueue.java:534)
E/AndroidRuntime(16200): at com.google.firebase.firestore.util.AsyncQueue$$Lambda$3.run(Unknown Source:2)
E/AndroidRuntime(16200): at android.os.Handler.handleCallback(Handler.java:883)
E/AndroidRuntime(16200): at android.os.Handler.dispatchMessage(Handler.java:100)
E/AndroidRuntime(16200): at android.os.Looper.loop(Looper.java:214)
E/AndroidRuntime(16200): at android.app.ActivityThread.main(ActivityThread.java:7356)
E/AndroidRuntime(16200): at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(16200): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
E/AndroidRuntime(16200): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
E/AndroidRuntime(16200): Caused by: java.lang.RuntimeException: android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5 SQLITE_BUSY)
E/AndroidRuntime(16200): at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor.lambda$executeAndReportResult$1(AsyncQueue.java:325)
E/AndroidRuntime(16200): at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor$$Lambda$2.run(Unknown Source:4)
E/AndroidRuntime(16200): at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462)
E/AndroidRuntime(16200): at java.util.concurrent.FutureTask.run(FutureTask.java:266)
E/AndroidRuntime(16200): at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
E/AndroidRuntime(16200): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
E/AndroidRuntime(16200): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E/AndroidRuntime(16200): at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor$DelayedStartFactory.run(AsyncQueue.java:229)
E/AndroidRuntime(16200): at java.lang.Thread.run(Thread.java:919)
E/AndroidRuntime(16200): Caused by: android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5 SQLITE_BUSY)
E/AndroidRuntime(16200): at android.database.sqlite.SQLiteConnection.nativeExecute(Native Method)
E/AndroidRuntime(16200): at android.database.sqlite.SQLiteConnection.execute(SQLiteConnection.java:648)
E/AndroidRuntime(16200): at android.database.sqlite.SQLiteSession.beginTransactionUnchecked(SQLiteSession.java:325)
E/AndroidRuntime(16200): at android.database.sqlite.SQLiteSession.beginTransaction(SQLiteSession.java:300)
E/AndroidRuntime(16200): at android.database.sqlite.SQLiteDatabase.beginTransaction(SQLiteDatabase.java:568)
E/AndroidRuntime(16200): at android.database.sqlite.SQLiteDatabase.beginTransactionWithListener(SQLiteDatabase.java:531)
E/AndroidRuntime(16200): at com.google.firebase.firestore.local.SQLitePersistence.runTransaction(SQLitePersistence.java:190)
E/AndroidRuntime(16200): at com.google.firebase.firestore.local.LocalStore.startMutationQueue(LocalStore.java:159)
E/AndroidRuntime(16200): at com.google.firebase.firestore.local.LocalStore.start(LocalStore.java:155)
E/AndroidRuntime(16200): at com.google.firebase.firestore.core.ComponentProvider.initialize(ComponentProvider.java:138)
E/AndroidRuntime(16200): at com.google.firebase.firestore.core.FirestoreClient.initialize(FirestoreClient.java:249)
E/AndroidRuntime(16200): at com.google.firebase.firestore.core.FirestoreClient.lambda$new$0(FirestoreClient.java:96)
E/AndroidRuntime(16200): at com.google.firebase.firestore.core.FirestoreClient$$Lambda$1.run(Unknown Source:8)
E/AndroidRuntime(16200): at com.google.firebase.firestore.util.AsyncQueue.lambda$enqueue$2(AsyncQueue.java:436)
E/AndroidRuntime(16200): at com.google.firebase.firestore.util.AsyncQueue$$Lambda$2.call(Unknown Source:2)
E/AndroidRuntime(16200): at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor.lambda$executeAndReportResult$1(AsyncQueue.java:322)
E/AndroidRuntime(16200): ... 8 more
I/Process (16200): Sending signal. PID: 16200 SIG: 9
Lost connection to device.
I only get this error when I have multiple firebase projects being initialized and am re-starting the app (without restarting the emulator).
Do you know what is causing this error and how to fix it?
Code:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(App());
}
class App extends StatefulWidget {
#override
_AppState createState() => _AppState();
}
class _AppState extends State<App> {
#override
void initState() {
print("Constructing app");
super.initState();
}
final Future<FirebaseApp> firebaseApp = Firebase.initializeApp(
options: FirebaseOptions(
apiKey: "api-key-1",
appId: "app-id-1",
projectId: "project-id-1",
messagingSenderId: "sender-id-1"));
final Future<FirebaseApp> firebaseAppDiscussions = Firebase.initializeApp(
options: FirebaseOptions(
apiKey: "api-key-2",
appId: "app-id-2",
projectId: "project-id-2",
messagingSenderId: "sender-id-2"),
name: "app2");
final Future<FirebaseApp> firebaseAppComments = Firebase.initializeApp(
options: FirebaseOptions(
apiKey: "api-key-3",
appId: "app-id-3",
projectId: "project-id-3",
messagingSenderId: "sender-id-3"),
name: "app3");
// My app also uses Shared Preferences, but I am not sure if it is playing a part in causing this error.
final Future<SharedPreferences> sharedPrefStore = SharedPreferences.getInstance();
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
home: FutureBuilder(
future: Future.wait([
firebaseApp,
sharedPrefStore,
firebaseAppDiscussions,
firebaseAppComments
]),
builder: (context, AsyncSnapshot<List<dynamic>> snapshot) {
auth = FirebaseAuth.instance;
authDiscussion = FirebaseAuth.instanceFor(app: snapshot.data![2]);
authComment = FirebaseAuth.instanceFor(app: snapshot.data![3]);
firestoreInstance = FirebaseFirestore.instance;
firestoreInstanceDiscussion = FirebaseFirestore.instanceFor(app: snapshot.data![2]);
firestoreInstanceComment = FirebaseFirestore.instanceFor(app: snapshot.data![3]);
prefs = snapshot.data![1]; // sharedPrefStore
// If I comment out the if statement below, the app will work.
// However, with the if statement, a crash is certain.
if (auth.currentUser?.uid == null) {
print("No user logged in");
}
return Text("App has loaded");
}
);
}
}
Steps to produce error:
Start the emulator and run the app by pressing the green arrow button
After the app is up and running, press the red button to stop execution.
Restart the app by pressing the green arrow button
Additional information:
Each Firebase project is using Cloud Firestore and Firebase Auth, which I have initialized inside future builder in the following manner:
auth = FirebaseAuth.instance;
authDiscussion = FirebaseAuth.instanceFor(app: snapshot.data![2]);
authComment = FirebaseAuth.instanceFor(app: snapshot.data![3]);
firestoreInstance = FirebaseFirestore.instance;
firestoreInstanceDiscussion = FirebaseFirestore.instanceFor(app: snapshot.data![2]);
firestoreInstanceComment = FirebaseFirestore.instanceFor(app: snapshot.data![3]);
prefs = snapshot.data![1]; // sharedPrefStore
When I start the app the first time, I have absolutely no errors and all three projects can access their respective Cloud Firestores and Firebase Auth.
Also, I am testing my app on the Pixel 2 (API 29) emulator provided by Android Studio.
I have been searching online for solutions, but most people encounter this error when using Firebase with persistence enabled (ex: Firebase Database crash SQLiteDatabaseLockedException) -- which I am not using.
I have tried disabling shared preferences, but to no avail. The app still crashes when performing a re-start.
My hypothesis:
I have a hunch that when I re-run the app, it re-constructs App which in turn reinitializes my three firebase projects leading to the error. I tried to validate this theory by placing a print inside the initializeState() method in App to track when App is re-constructed. And sure enough, whenver initializeState() is called more than once, my app crashes.
But I have no idea how I can "tell" the app to not reinitialize the projects.
Edit #1:
I understand the error is concerned with SQLite Database being locked. However, (I don't think) I am using any such database. I don't use sqflite; instead, my app uses shared preferences to persist data locally (as it only persists a small amount of data), and that's it.
Edit #2:
I have updated my code snippet above to include the entire code that I was testing. As you can see, I don't explicitly initialize SQL database anywhere. So, it is likely that Firebase.initializeApp uses/locks SQL database internally. And since I have multiple calls to Firebase.initializeApp -- all which will access the same SQL database -- the calls block on each other resulting in the error "SQL database locked."
If this is indeed the case, the error should go away if I wait for each Firebase.initializeApp call to complete before calling it again for the next Firebase project.
This is my current theory, and I am working to modify my code initialize my firebase projects one after the other.
Solution:
My theory (mentioned in "Edit #2") was valid. I modified my code as stated above and all the errors went away.
Here's my complete, working code with comments.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
/// Here is my updated code that initializes Firebase projects one after another to ensure they don't clash on the SQL database.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
print("Constructing my app");
super.initState();
}
final Future<SharedPreferences> sharedPrefStore =
SharedPreferences.getInstance(); // This is used by my app later on and is not really relevant to the error.
// Functions to initialize all 3 apps. I use these functions only help make the code look cleaner.
Future<FirebaseApp> initFirebase3() {
return Firebase.initializeApp(
options: FirebaseOptions(
apiKey: "api-key3",
appId: "app-id3",
projectId: "project-id3",
messagingSenderId: "sender-id3"),
name: "app3");
}
Future<FirebaseApp> initFirebase2() {
return Firebase.initializeApp(
options: FirebaseOptions(
apiKey: "api-key2",
appId: "app-id2",
projectId: "project-id2",
messagingSenderId: "sender-id2"),
name: "app2");
}
Future<FirebaseApp> initFirebaseDefault() {
return Firebase.initializeApp(
options: FirebaseOptions(
apiKey: "api-key1",
appId: "app-id1",
projectId: "project-id1",
messagingSenderId: "sender-id1"));
}
#override
Widget build(BuildContext context) {
print("Building App.");
return MaterialApp(
title: 'My App',
home: FutureBuilder(
// sharedPrefStore and Firebase.initializeApp can run in parallel since they are independent of each other.
future: Future.wait([initFirebaseDefault(), sharedPrefStore]),
builder: (context, AsyncSnapshot<List<dynamic>> snapshot) {
if (snapshot.hasError) {
print("You have an error! ${snapshot.error.toString()}");
return Text('Oops! Something went wrong. Please try again');
} else if (snapshot.hasData) {
// Initialize firestore and auth (global variables) using the completed future
auth = FirebaseAuth.instance;
firestoreInstance = FirebaseFirestore.instance;
prefs = snapshot.data![1]; // sharedPrefStore
// Now on to app2. Before we initialize app2, we must first check if it already exists.
// If it already exists and we try to initialize it again, we will get the error "app2 already exists"
late FirebaseApp? app2;
try {
app2 = Firebase.app("app2");
} catch (e) {
print("app2 not initialized");
app2 = null;
}
if (app2 != null) {
auth2 = FirebaseAuth.instanceFor(app: app2);
firestoreInstance2 = FirebaseFirestore.instanceFor(app: app2);
// Same as above. Before we initialize app3, we must first check if it already exists.
// If it already exists and we try to initialize it again, we will get the error "app3 already exists"
late FirebaseApp? app3;
try {
app3 = Firebase.app("app3");
} catch (e) {
print("app3 not initialized");
app3 = null;
}
if (app3 == null) {
return FutureBuilder(
future: initFirebase3(),
builder:
(context, AsyncSnapshot<FirebaseApp> snapshot) {
if (snapshot.hasError) {
print(
"You have an error! ${snapshot.error.toString()}");
return Text(
'Oops! Something went wrong. Please try again');
} else if (snapshot.hasData) {
auth3 = FirebaseAuth.instanceFor(app: snapshot.data!);
firestoreInstance3 = FirebaseFirestore.instanceFor(
app: snapshot.data!);
return Scaffold(
body: Text("app has loaded"),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
});
} else {
auth3 = FirebaseAuth.instanceFor(app: app3);
firestoreInstance3 = FirebaseFirestore.instanceFor(app: app3);
return Scaffold(
body: Text("app has loaded"),
);
}
}
// app2 was null so we came here; now we must initialize app2
return FutureBuilder(
future: initFirebase2(),
builder: (context, AsyncSnapshot<FirebaseApp> snapshot) {
if (snapshot.hasError) {
print(
"You have an error! ${snapshot.error.toString()}");
return Text(
'Oops! Something went wrong. Please try again');
} else if (snapshot.hasData) {
auth2 = FirebaseAuth.instanceFor(app: snapshot.data!);
firestoreInstance2 =
FirebaseFirestore.instanceFor(app: snapshot.data!);
// I assume that if app2 was not initialized neither was app3, hence I call initFirebase3().
return FutureBuilder(
future: initFirebase3(),
builder:
(context, AsyncSnapshot<FirebaseApp> snapshot) {
if (snapshot.hasError) {
print(
"You have an error! ${snapshot.error.toString()}");
return Text(
'Oops! Something went wrong. Please try again');
} else if (snapshot.hasData) {
auth3 = FirebaseAuth.instanceFor(
app: snapshot.data!);
firestoreInstance3 =
FirebaseFirestore.instanceFor(
app: snapshot.data!);
return Scaffold(
body: Text("app has loaded"),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
});
} else {
return Center(
child: CircularProgressIndicator(),
);
}
});
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}));
}
}
Please let me know if additional information is needed. Any help would be greatly appreciated.
Thank you

It's not a firebase issue, it's an SQFlite issue. The error says:
Caused by: android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5 SQLITE_BUSY)
E/AndroidRuntime(16200)
It has something to do with what happens in your code after you initialize the apps. If you are fetching magnitudes of data, causing heavy writes to your SQFlite database, it causes it to lock.

Related

Android Studio Flutter Android App issues with Work Manager and Sqflite Working together

I am having an issue when work managers scheduler runs it gets stuck on reading data from database:
Future<List<TimesheetDays>> getTimesheetDays() async{
print('Getting DB');
Database db = await instance.database;
print('Getting DB stuff');
var timesheetday = await db.query('TimesheetDays',orderBy: 'TimesheetDayId');
// print(timesheetday);
List<TimesheetDays> timesheetDaysList = timesheetday.isNotEmpty ?
timesheetday.map((e) => TimesheetDays.fromMap(e)).toList() : [];
return timesheetDaysList;
}
It gets stuck on the
await instance.database
part of the code, now strange thing is that I have this project set on PC and Laptop. It only fails to work on PC whereas its fine on Laptop.
Work Manager code in case:
Callback Dispatcher
void callbackDispatcher() {
Workmanager().executeTask((task, inputData) async {
print('Executed scheduler!!');
try {
print('entered try catch!');
await CustomHttpRequests().synchronizeTimesheetDataLocally();
}
catch(_){
print('Error during execution');
}
print('Completed synchronization');
return Future.value(true);
});
}
Rest of the code:
Future<void> main() async{
WidgetsFlutterBinding.ensureInitialized();
print('creating task manager');
await Workmanager().initialize(
callbackDispatcher, // The top level function, aka callbackDispatcher
isInDebugMode: true, // If enabled it will post a notification whenever the task is running. Handy for debugging tasks
);
Workmanager().registerPeriodicTask("1", fetchBackground, frequency: Duration(minutes: 15),initialDelay: Duration(minutes: 2)); //Android only (see below)
print('Task manager created');
runApp(
MultiProvider(providers: [
ChangeNotifierProvider(create: (_) => CoreUser())
],
child: MyApp(),)
);
}
And just so the call in dispatcher makes sense it references straight to database in its first line so this is where it fails:
Future synchronizeTimesheetDataLocally() async{
//await synchronizeWasteGradings();
print("started reading");
var timesheetData = await DatabaseHelper.instance.getTimesheetDays();
Some things I tried to do to fix it:
"flutter clean"
Made sure MainActivity and GeneratedPluginRegistrant are the same on both devices
(sqflite & work manager are both being registered properly)
Basically went through this:
https://github.com/tekartik/sqflite/blob/master/sqflite/doc/troubleshooting.md
Any ideas how to fix this?

When using Firebase login, it is always automatically logged in [duplicate]

Main Dart:
Widget build(BuildContext context) {
return StreamProvider<MyUser?>.value(
value: AuthService().user,
initialData: null,
child: MaterialApp( //code for material dart
Wrapper Widget:
Widget build(BuildContext context) {
final user = Provider.of<MyUser?>(context);
print(user);
if (user == null) {
print('no one logged in');
} else {
print(user.uid);
}
return user == null ? LoginPage() : NavigationBar();
}
So I'm trying to load the login page whenever user is null, but I only logged in the first time and now it stays logged in even after deleting that account from firebase console.
Output after hot restart:
Restarted application in 935ms.
flutter: null
flutter: no one logged in
flutter: Instance of 'MyUser'
flutter: ETBVvt2A0JggH8KSrgdLh3DP8cG3
I don't get why the first time it returns
'no one logged in' but it runs a second time too and returns the uid of the user that is logged in.
The logout button doesn't work either. It does't return an error or anything, it just doesn't produce any output.
Here is the signOut button method:
//method
final FirebaseAuth _auth = FirebaseAuth.instance;
Future signOut() async {
try {
return await _auth.signOut();
} catch (error) {
print(error.toString());
return null;
}
Signout button:
onPressed: () async {
dynamic result = await _auth.signOut();
if (result == null) {
print('error signing out');
} else {
print('signed out');
Navigator.pushReplacementNamed(
context, LoginPage.routeName);
}
},
Firebase automatically persists the user credentials locally, and tries to restore those when the app is restarted.
To sign the user out, you have to explicitly sign the user out by calling await FirebaseAuth.instance.signOut().
Apparently the problem wasn't with firebase but with the custom button I had built. I didn't assign the onPressed properly and the logout button wasn't working because of that.
Please call this function in your oppressed area
Future<Null> _signOut() async { await GoogleSignIn().signOut(); print("logout Successfully"); }
Here GoogleSignIn(), is the function where you define your signin codes

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: Exception caught by Streambuilder

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!

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