Flutter Firestore Read Write Response Very Slow in Ios - ios

I have added flutter firestore my ios app. The read-write update delete request to firestore is very quick as usual, but when I want to get the response of the read write update delete back from firestore server, it is very slow and fails sometimes.
The code for write and read in my main.dart is
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
final firestoreInstance = FirebaseFirestore.instance;
final auth = FirebaseAuth.instance;
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Future<void> adduser() async {
await firestoreInstance.collection("users").add({
"mob": 9344122678292,
"email": "usehhr5",
"name": {"fname": "Sub", "lname": "Collec"},
"array": [
"raw",
"pin",
"hot",
],
"time": FieldValue.serverTimestamp(),
}).then((value) {
print("added_data");
}).catchError((error) => print("Failed to add user: $error"));
}
Future<void> readdata() async {
await firestoreInstance.collection("users").get().then((querySnapshot) {
//firestoreInstance.clearPersistence();
querySnapshot.docs.forEach((result) {
print(result.data());
print("read_data");
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
//adduser();
readdata();
},
tooltip: 'Read/Add data',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
So i want to get the response from read and write in print() statemen, but it takes 2-3 seconds to get the response and some times i get this error message in log
console response
Also sometime get this response
7.3.0 - [Firebase/Firestore][I-FST000001] Could not reach Cloud Firestore backend. Backend didn't respond within 10 seconds.
This typically indicates that your device does not have a healthy Internet connection at the moment. The client will operate in offline mode until it is able to successfully connect to the backend.
and this repsonse
[BackgroundTask] Background Task 22 ("GTMSessionFetcher-www.googleapis.com"), was created over 30 seconds ago. In applications running in the background, this creates a risk of termination. Remember to call UIApplication.endBackgroundTask(_:) for your task in a timely manner to avoid this.
Please provide help, I tried the read and write response from firestore in ios emulator and a physical android device, it was perfect. I was getting instant response from the firesotre server. The issue is showing when i run the app in physical ios device running ios 14.4

As it seems, you are calling async methods directly from the StatefulWidget , that's not good. Those async methods are interacting with Firestore , and any slowness will directly affect the user experience.
few suggestions:
accessing Firestore right from the widget is not the right way. This will your app unresponsive.
Widgets should be responsible for the user interaction and be responsive.
Data processing (Firestore etc) should be handled by BLoC and be done in an async way. State management plays essential role in building Flutter apps.

Related

Flutter Bloc - Register Handler issue

I am looking for some help with my code. I want to create some swappable cards and for that I have created blocs. However, when I finished and tried to launch it, following message appears :
Bad state: add(LoadMissionsEvent) was called without a registered event handler.
Make sure to register a handler via on((event, emit) {...})
class MyApp extends StatelessWidget {
const MyApp({
Key key,
}) : super(key: key);
// final StreamChatClient client;
// final Channel channel;
#override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (_) => SwipeBloc()
..add(LoadMissionsEvent(
missionDescriptions:
MissionDescription.missionsDescriptions)))
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: "Student App",
home: MissionChoice(),
localizationsDelegates: [GlobalMaterialLocalizations.delegate],
supportedLocales: [Locale('en'), Locale('fr')],
// Scaffold(
// backgroundColor: d_green,
// ),
));
}
}

Flutter setState() function being called but not doing anything

Managed to create a simple reproduction of an error I've come across in my real program, and I'm not sure why this kind of a thing happens. I think if I can understand this, it might help me.
The key here is that I HAVE to have the two pieces of the program separated in this manner, and they need to communicate, but that communication isn't happening the way I would expect. (So please don't suggest I put the timer function inside the rest of the program).
import 'package:flutter/material.dart';
import 'dart:async';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool textBool = false;
void textChanger() {
if (textBool) {
setState(() {
textBool = false;
});
} else {
setState(() {
textBool = true;
});
}
}
Text myText() {
if (textBool) {
Text newText = new Text('Original Text');
return newText;
} else {
Text newText = new Text('New Text');
return newText;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: myText(),
),
floatingActionButton: FloatingActionButton(
onPressed: stateModify,
tooltip: 'Change Text',
),
);
}
}
Future<void> stateModify() {
Duration waitTimer = new Duration(seconds: 5);
new Timer.periodic(waitTimer, (timer) {
_MyHomePageState().textChanger();
timer.cancel();
});
}
Expected functionality: Click the button and 5 seconds later it should change to the second set of text. Then I should be able to click the button again and switch it back.
Instead in this example I receive the following error:
[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: setState() called in constructor: _MyHomePageState#a5177(lifecycle state: created, no widget, not mounted)
And google doesn't seem to be super helpful on this particular issue.
Any suggestions?
Your stateModify function is not a method of _MyHomePageState. Also when you are accessing the _MyHomePageState().textChanger() in stateModify you are eventually creating a new object of _MyHomePageState() but not inserting in render tree.
You should use Timer instead of Timer.periodic. The Timer.periodic will repeat the task until the Timer.cancel is called. Timer will do a callback after the given time period which you require.
Pass the function textChanger when you are calling stateModify that way you will be able to call the function of _MyHomePageState without creating a new object.
Do the following changes.
floatingActionButton: FloatingActionButton(
onPressed: ()=> stateModify(textChanger),
tooltip: 'Change Text',
),
stateModify(dynamic function) {
Timer(Duration(seconds: 5), function);
}

refresh the data from network using future builder on clicking the onpressed action from another dart class

I have a stateful widget class app_body.dart and which will fetch some data from the API and display using the future builder.
below is the sample code from app_body.dart
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import './my_app_bar.dart';
class AppBody extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _AppBodyState();
}
}
class _AppBodyState extends State<AppBody> {
Future _fetchLogData() async {
final response = await http.get('api url');
if (response.statusCode == 200) {
return UserDetailHandler.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load post');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppBar(_fetchLogData),
body: Center(
child: FutureBuilder(
future: _fetchLogData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Container(
child: Column(children: <Widget>[
Text('Last Synced' + ' ' + snapshot.data.lastUpdatedAt)]));
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
),
),
);
}
}
// class which instantiate all the details from the API Part
class UserDetailHandler {
final String lastUpdatedAt;
// constructor to intialise
UserDetailHandler({this.lastUpdatedAt});
// assign values to the class object
factory UserDetailHandler.fromJson(Map<String, dynamic> json) {
return UserDetailHandler(lastUpdatedAt: json['updated_at']);
}
}
Also upon clicking on the refresh icon on another stateless class called my_app_bar.dart which holds the
AppBar and actions to be performed. My aim is to refresh the data displayed in the app_body.dart
To do that, I just passed my API calling method to the stateless widget and call it on the onPressed action of
the my_app_bar refresh button. The API is called, but the data is not refreshed.
Below is the sample code from my_app_bar.dart
import 'package:flutter/material.dart';
class MyAppBar extends StatelessWidget implements PreferredSizeWidget {
final Function refreshLogData;
MyAppBar(this.refreshLogData);
#override
Widget build(BuildContext context) {
return AppBar(
actions: <Widget>[
IconButton(
icon: new Icon(Icons.refresh),
alignment: Alignment.topCenter,
tooltip: 'refresh the Data',
onPressed: () {
print('log data');
refreshLogData();
},
)
],
title: Center(
child: Text(
'Random Data',
textAlign: TextAlign.center,
)));
}
#override
Size get preferredSize => new Size.fromHeight(kToolbarHeight);
}
Am I missing something or do I need to do extra above said. I have found much articles to refresh the data when the button is present in the AppBody part. Here, My code has 2 files and the refresh icon is existed in another class of appBar.
Please advise, TIA.
From the provided code change these lines
........
IconButton(
.....
.....
onPressed: refreshLogData,
)
],
.........
then the refreshLogData method will work and after completion of Server call, you need to refresh the screen using setState.
A better suggestion is instead of Future use StreamBuilder then it will work seamlessly.

Flutter Globals losing their value

Okay, I am sure this is probably an easy to answer question, but after much searching I can't put my finger on the solution.
How does one in Flutter/Dart create a variable in app XYZ that maintains its' value during the time a user moves away from the app, uses another app, allows the phone to go to sleep, etc., then opens the XYZ app again.
I've created a tiny little app that demonstrates the issue as shown below.
The static variable Globals.UID can be incremented upwards, but if the app is moved away from (what term describes using another app correctly?) then as noted the phone goes to sleep, when the user comes back to the app the Globals.UID variable is reset back to -1.
Sometimes the reset is not immediate and I have to let the IOS phone sleep for perhaps 5 minutes to recreate the behavior.
Basically I need Globals.UID to retain its' value until the app is actually exited.
Any insight would truly be appreciated.
import 'package:flutter/material.dart';
import 'package:test_flutter/Globals.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
Globals.UID ++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
Text ( "Global variable is:")
, Text ( Globals.UID.toString() )
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
And in a different file called Globals.dart
class Globals {
static int UID = -1;
}
Thank you!
Ultimately, the solution appears to be solved mostly by using the shared_preferences library. That solution brings with it a good many documented problems, but to maintain data while the app is placed in the background, or even killed by perhaps the user, shared_preferences appears to be the way to go.
Actually this happens to when you don't import with reference. This is a known issues which is already fixed, may be not landed yet. You can check the issue here.
Please try import package_name/globals.dart instead of just import globals.dart if you are doing so.
Hope that helps!

Flutter iOS Google maps: weird appear animation

I'm having an issue with Flutter Google maps official plugin on iOS both in debug and release builds which occurs when you open an app from a terminated state. No issue on Android
There's a weird appear animation playing when I have Google Map in my widget, especially it's annoying when there's a centered floating action button as well, it has some slide in animation too
Check this video https://www.youtube.com/watch?v=94ee6cePbWw&feature=youtu.be
If you play it frame by frame, you'll see that app bar is colored correctly, floating action button is drawn, but then everything is flashed white and floating action button suddenly plays a slide in appearing animation, when it was already displayed. It all looks very glitchy
If I remove Google map from my widget, everything works fine: there's no FAB slide in animation and app bar is not flashed white, after they were drawn.
Running on Flutter v1.1.4. I want to get rid of this appear animation, thanks for the support
Here's my code
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: '',
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(title: ''),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('')),
body: GoogleMap(
onMapCreated: (controller) {},
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
You should realize that this is a developer preview. Until the version number hits 1.0, all bets are off about how well it performs, and even if it's suitable.

Resources