I\'m new to the flutter world and mobile app development and struggling with how I should pass user data throughout my app.
I\'ve tried several things, but none seem gre
I'd recommend investigating inherited widgets further; the code below shows how to use them with asynchronously updating data:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(new MaterialApp(
title: 'Inherited Widgets Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new Scaffold(
appBar: new AppBar(
title: new Text('Inherited Widget Example'),
),
body: new NamePage())));
}
// Inherited widget for managing a name
class NameInheritedWidget extends InheritedWidget {
const NameInheritedWidget({
Key key,
this.name,
Widget child}) : super(key: key, child: child);
final String name;
@override
bool updateShouldNotify(NameInheritedWidget old) {
print('In updateShouldNotify');
return name != old.name;
}
static NameInheritedWidget of(BuildContext context) {
// You could also just directly return the name here
// as there's only one field
return context.inheritFromWidgetOfExactType(NameInheritedWidget);
}
}
// Stateful widget for managing name data
class NamePage extends StatefulWidget {
@override
_NamePageState createState() => new _NamePageState();
}
// State for managing fetching name data over HTTP
class _NamePageState extends State<NamePage> {
String name = 'Placeholder';
// Fetch a name asynchonously over HTTP
_get() async {
var res = await http.get('https://jsonplaceholder.typicode.com/users');
var name = json.decode(res.body)[0]['name'];
setState(() => this.name = name);
}
@override
void initState() {
super.initState();
_get();
}
@override
Widget build(BuildContext context) {
return new NameInheritedWidget(
name: name,
child: const IntermediateWidget()
);
}
}
// Intermediate widget to show how inherited widgets
// can propagate changes down the widget tree
class IntermediateWidget extends StatelessWidget {
// Using a const constructor makes the widget cacheable
const IntermediateWidget();
@override
Widget build(BuildContext context) {
return new Center(
child: new Padding(
padding: new EdgeInsets.all(10.0),
child: const NameWidget()));
}
}
class NameWidget extends StatelessWidget {
const NameWidget();
@override
Widget build(BuildContext context) {
final inheritedWidget = NameInheritedWidget.of(context);
return new Text(
inheritedWidget.name,
style: Theme.of(context).textTheme.display1,
);
}
}
You can use the GetX package to check whether or not the user is logged in, get user data and have it accessible throughout your app
I crashed into another problem because of this problem you can check it out here So the solution I came up with is a bit untidy,I created a separate Instance dart page and imported it to every page.
GoogleSignInAccount Guser = googleSignIn.currentUser;
FirebaseUser Fuser;
I stored the user there on login and checked on every StateWidget if it was null
Future<Null> _ensureLoggedIn() async {
if (Guser == null) Guser = await googleSignIn.signInSilently();
if (Fuser == null) {
await googleSignIn.signIn();
analytics.logLogin();
}
if (await auth.currentUser() == null) {
GoogleSignInAuthentication credentials =
await googleSignIn.currentUser.authentication;
await auth.signInWithGoogle(
idToken: credentials.idToken,
accessToken: credentials.accessToken,
);
}
This is my old code I did cleaned it up on my current app but I don't have that code now in handy. Just check out for null user and log it in again
I did it for most of the Firebase instances too because I have more than 3 pages on my app and Inherited Widgets was just too much work
For my lazy mathod, i just create new file like userdata.dart and then put any variable on it for example like dynamic Profile = null
inside userdata.dart
//only put this or anything u want.
dynamic Profile = null;
at startingpage.dart
//import that file
import '../userdata.dart';
class startingpage extends ...{
...
//set data to store..
Profile = 'user profile';
...
}
to use the data just declare and use in anotherpage.dart
//import that file
import '../userdata.dart';
class anotherpage extends...{
...
}
class .. State ...{
...
//set the data to variable
dynamic userdata = Profile;
print('this is my lazy pass data' + userdata.toString());
...
}
I prefer to use Services with Locator, using Flutter get_it.
Create a UserService with a cached data if you like:
class UserService {
final Firestore _db = Firestore.instance;
final String _collectionName = 'users';
CollectionReference _ref;
User _cachedUser; //<----- Cached Here
UserService() {
this._ref = _db.collection(_collectionName);
}
User getCachedUser() {
return _cachedUser;
}
Future<User> getUser(String id) async {
DocumentSnapshot doc = await _ref.document(id).get();
if (!doc.exists) {
log("UserService.getUser(): Empty companyID ($id)");
return null;
}
_cachedUser = User.fromDocument(doc.data, doc.documentID);
return _cachedUser;
}
}
Then create create a Locator
GetIt locator = GetIt.instance;
void setupLocator() {
locator.registerLazySingleton(() => new UserService());
}
And instantiate in main()
void main() {
setupLocator();
new Routes();
}
That's it! You can call your Service + cachedData everywhere using:
.....
UserService _userService = locator<UserService>();
@override
void initState() {
super.initState();
_user = _userService.getCachedUser();
}