Flutter initState called every time I re-enter a page - flutter

I have three pages, A, B, C, and I navigate between them through a Drawer.
My goal is to get initState to be called only once (when the page is inserted in the widget tree), so that the state of each page is not reinitialized when I return to it.
My fist try was to use Navigator.of(context).PushNamed(routeName) as shown in the code below.
Probably this doesn't work because if from A I call B and then A again, the navigator stack is
[A] --> [B, A] --> [A, B, A] and not
[A] -> [B, A] --> [A]
so a navigation based on pop() should be more appropriate. I tried with
onTap: () {
Navigator.of(context).canPop()
? Navigator.of(context)
.popUntil(ModalRoute.withName(PageA.routeName))
: Navigator.of(context).pushNamed(PageA.routeName);
},
instead of onTap: () => Navigator.of(context).pushNamed(PageA.routeName)
But it doesn't work: when I tap on a drawer item a black screen appears, without any exception or warning, as if the navigator called a blank screen...
What am I doing wrong? Any idea how to fix?
This is my code:
main.dart
import 'package:flutter/material.dart';
import 'page_c.dart';
import 'page_a.dart';
import 'page_b.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Navigation test',
home: PageA(),
routes: {
PageA.routeName: (ctx) => PageA(),
PageB.routeName: (ctx) => PageB(),
PageC.routeName: (ctx) => PageC(),
},
);
}
}
my_drawer.dart
import 'package:flutter/material.dart';
import 'page_b.dart';
import 'page_c.dart';
import 'page_a.dart';
class MyDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: [
SizedBox(
height: 100,
),
ListTile(
title: Text('PAGE A'),
onTap: () => Navigator.of(context).pushNamed(PageA.routeName)),
ListTile(
title: Text('PAGE B'),
onTap: () => Navigator.of(context).pushNamed(PageB.routeName)),
ListTile(
title: Text('PAGE C'),
onTap: () => Navigator.of(context).pushNamed(PageC.routeName)),
],
),
);
}
}
page_a.dart
import 'package:flutter/material.dart';
import 'my_drawer.dart';
class PageA extends StatefulWidget {
static const routeName = '/route-a';
#override
_PageAState createState() => _PageAState();
}
class _PageAState extends State<PageA> {
#override
void initState() {
print('PAGE A INIT STATE');
super.initState();
}
// void didChangeDependencies() {
// print('PAGE A DID CHANGE DEPENDECIES');
// super.didChangeDependencies();
// }
// #override
// void dispose() {
// print('PAGE A DISPOSE');
// super.dispose();
// }
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('PAGE A')),
drawer: MyDrawer(),
body: Center(
child: Text('A', style: TextStyle(fontSize: 100)),
),
);
}
}
page_b.dart
import 'package:flutter/material.dart';
import 'my_drawer.dart';
class PageB extends StatefulWidget {
static const routeName = '/route-b';
#override
_PageBState createState() => _PageBState();
}
class _PageBState extends State<PageB> {
#override
void initState() {
print('PAGE B INIT STATE');
super.initState();
}
// void didChangeDependencies() {
// print('PAGE B DID CHANGE DEPENDECIES');
// super.didChangeDependencies();
// }
// #override
// void dispose() {
// print('PAGE B DISPOSE');
// super.dispose();
// }
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('PAGE B')),
drawer: MyDrawer(),
body: Center(
child: Text('B', style: TextStyle(fontSize: 100)),
),
);
}
}
page_c.dart
import 'package:flutter/material.dart';
import 'my_drawer.dart';
class PageC extends StatefulWidget {
static const routeName = '/route-c';
#override
_PageCState createState() => _PageCState();
}
class _PageCState extends State<PageC> {
#override
void initState() {
print('PAGE C INIT STATE');
super.initState();
}
// void didChangeDependencies() {
// print('PAGE C DID CHANGE DEPENDECIES');
// super.didChangeDependencies();
// }
// #override
// void dispose() {
// print('PAGE C DISPOSE');
// super.dispose();
// }
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('PAGE C')),
drawer: MyDrawer(),
body: Center(
child: Text('C', style: TextStyle(fontSize: 100)),
),
);
}
}

Related

How to Refresh State from Navigator Pop in Flutter

I want to refresh the state when calling Navigator Pop / Navigator Pop Until.
While I was doing some research, I finally found this article Flutter: Refresh on Navigator pop or go back. From the code in the article, it can work fine.
But there is a problem when I use the widget tree, for example like the code below:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Refresh on Go Back',
home: HomePage(),
);
}
}
Home Page - Parent Class
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int id = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Data: $id',
style: Theme.of(context).textTheme.headline5,
),
ButtonWidget(),
],
),
),
);
}
void refreshData() {
id++;
}
onGoBack(dynamic value) {
refreshData();
setState(() {});
}
}
Button Widget - Widget Class
class ButtonWidget extends StatelessWidget{
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) =>
SecondPage())).then(onGoBack);
// The Problem is Here
// How to call a Method onGoBack from HomePage Class
}
);
}
}
SecondPage
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go Back'),
),
),
);
}
}
Or is there another solution to refresh the state class when calling Navigator Pop / Navigator Pop Until?
re-write your Button's class like this:
class ButtonWidget extends StatelessWidget{
final Function onGoBack;
ButtonWidget({this.onGoBack})
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) =>
SecondPage())).then(onGoBack);
//to avoid any np exception you can do this: .then(onGoBack ?? () => {})
// The Problem is Here
// How to call a Method onGoBack from HomePage Class
}
);
}
}
And add the onGoBack function as a parameter from the home page like this:
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int id = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Data: $id',
style: Theme.of(context).textTheme.headline5,
),
ButtonWidget(onGoBack: onGoBack),
],
),
),
);
}
void refreshData() {
id++;
}
onGoBack(dynamic value) {
refreshData();
setState(() {});
}
}
you must sent function on widget
class ButtonWidget extends StatelessWidget{
final Function(dynamic)? refresh;
const ButtonWidget({this.refresh})
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: ()async {
await Navigator.push(context, MaterialPageRoute(builder: (context) =>
SecondPage()));
if(refresh!=null){
refresh!("your params");
}
// The Problem is Here
// How to call a Method onGoBack from HomePage Class
}
);
}
}
and you can use widget
ButtonWidget(
refresh:onGoBack
)
Try this, it just you are calling method out of scope
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Refresh on Go Back',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int id = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Data: $id',
style: Theme.of(context).textTheme.headline5,
),
ButtonWidget(
refresh: onGoBack,
)
],
),
),
);
}
void refreshData() {
id++;
}
onGoBack(dynamic value) {
refreshData();
setState(() {});
}
}
class ButtonWidget extends StatelessWidget {
final Function(dynamic)? refresh;
ButtonWidget({Key? key, this.refresh}) : super(key: key);
#override
Widget build(BuildContext context) {
print(refresh);
return RaisedButton(onPressed: () async {
await Navigator.push(
context, MaterialPageRoute(builder: (context) => SecondPage()))
.then((value) => refresh!("okay"));
});
}
}
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go Back'),
),
),
);
}
}

Flutter: Continuation of the future

I go from page 1 to page 2. The counting process starts on page 2. As this continues, I return to page 1. Even if I exit page 2, the process continues. Why is this happening? How can I prevent this?
Future.delayed keeps working when I return to page 1 from page 2.
This is page 1. There is only one button to go to page 2.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:untitled1/page2.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.black38,
),
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => Page2()));
},
child: Text(
'Page 2',
),
),
],
),
),
);
}
}
This is page 2.
import 'package:flutter/material.dart';
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage2(),
);
}
}
class MyHomePage2 extends StatefulWidget {
#override
_MyHomePage2State createState() => _MyHomePage2State();
}
class _MyHomePage2State extends State<MyHomePage2> {
int d=0;
#override
void initState() {
// TODO: implement initState
for (int c = 0; c < 25; c++) {
Future.delayed(Duration(seconds: c), () {
setState(() {
d++;
});
});
}
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
' $d',
),
],
),
),
);
}
}
if(!mounted){
return;
}
It happened thanks to the above. If I write one, it will probably suffice. I don't know if this is a valid solution.
void initState() {
// TODO: implement initState
for (int c = kk; c < 25; c++) {
if(!mounted){
return;
}
Future.delayed(Duration(seconds: c), () {
if(!mounted){
return;
}
setState(() {
d++;
});
});
if(!mounted){
return;
}
}
super.initState();
}

How to update the state(Provider state) inside the initState function in Flutter?

I want to fetch data from an API and set those data to the central state(provider) after creating a screen.( similar scenario of react useEfect function)
class MyApp2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<Counter>(
child: MyHomePage(title: 'Flutter Demo Home Page'),
create: (BuildContext context) => Counter());
}
}
class _MyHomePageState extends State<MyHomePage> {
void _incrementCounter(dynamic count) {
count.incrementCounter();
}
int fetchData() {
//api request code
return data; // return fetched data
}
#override
Widget build(BuildContext context) {
final count = Provider.of<Counter>(context);
count.setCounter(fetchData());
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(
'${count.counter}',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _incrementCounter(count),
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class Counter with ChangeNotifier{
int counter= 0;
void setCounter(int x){
counter =x;
notifyListeners();
}
void clearCounter(){
counter =0;
notifyListeners();
}
void incrementCounter(){
counter++;
notifyListeners();
}
}
It throws and exception and it doesn't work.
setState() or markNeedsBuild() called during build.
If I remove the notifyListeners() function, the app runs without any exceptions but the widget what I want to rebuild isn't rebuilt.
void setCounter(int x){
counter =x;
// notifyListeners();
}
What is the best way to do that?
I am also new to Provider. So this may not be a good solution.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: MyApp2(),
);
}
}
class MyApp2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<Counter>(
child: MyHomePage(title: 'Flutter Demo Home Page'),
create: (BuildContext context) => Counter(),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({Key key, this.title}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Consumer<Counter>(
builder: (context, counter, _) {
if (counter.waiting)
return CircularProgressIndicator();
else
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Consumer<Counter>(
builder: (context, counter, _) {
return Text(
'${counter.counter}',
style: Theme.of(context).textTheme.display1,
);
},
),
],
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: Provider.of<Counter>(context).incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class Counter with ChangeNotifier {
int _counter;
bool _waiting;
Counter(){
_waiting = true;
_fetchCounterFromApi();
}
Future<void>_fetchCounterFromApi() async{
_counter = await Future<int>.delayed(Duration(seconds: 2),() => 4);//Do Api request;
_waiting = false;
notifyListeners();
}
int get counter => _counter;
bool get waiting => _waiting;
void incrementCounter() {
_counter++;
notifyListeners();
}
}

how to edit value at the child widget

i try to edit the value of the child widget, i can do it with StatefulWidget parent but i want to do it with StatelessWidget parent and without using global value
class Homepage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
FlatButton(child: Text('addFile'), onPressed: () {}),
FlatButton(child: Text('deleteFile'), onPressed: () {})
],
),
body: Child(),
);
}
}
class Child extends StatefulWidget {
#override
_ChildState createState() => _ChildState();
}
class _ChildState extends State<Child> {
var hasFile = true;
#override
Widget build(BuildContext context) {
return hasFile ? Text('has a file') : Text("no File");
}
}
You are thinking the wrong way. Child aka Text() should get its value from a model which is managed by the application or at least managed by the widget above. I would go with the provider package https://pub.dev/packages/provider and do this:
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
class MyState with ChangeNotifier {
String _myText;
MyState(this._myText);
getMyText() => _myText;
void changeText(String newText) {
_myText = newText;
notifyListeners();
}
}
class Homepage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(builder: (_) => MyState("initial Text")),
],
child: Scaffold(
appBar: AppBar(
actions: <Widget>[
FlatButton(
child: Text('addFile'),
onPressed: () {
Provider.of<MyState>(context).changeText("addFile");
}),
FlatButton(
child: Text('deleteFile'),
onPressed: () {
Provider.of<MyState>(context).changeText("deleteFile");
})
],
),
body: Child(),
));
}
}
class Child extends StatelessWidget {
#override
Widget build(BuildContext context) {
MyState myState = Provider.of<MyState>(context);
return Text(myState.getMyText());
}
}
This is coded without IDE support or even compiling and running. But it should get you to the right direction.
You can use BLoC pattern to implement this kind of functionality,
Here is the BLoC class which will handle state of bool
import 'dart:async';
class Bloc {
final _fileController = StreamController<bool>();
changeState(bool val) {
_fileController.sink.add(val);
}
get hasFile => _fileController.stream;
dispose() {
_fileController.close();
}
}
final bloc = Bloc();
Then you can add stream builder in your Stateful Widget, in which you will provide stream of BLoC class.
StreamBuilder updates it's UI according to Stream.
class Child extends StatefulWidget {
#override
_ChildState createState() => _ChildState();
}
class _ChildState extends State<Child> {
var hasFile = true;
#override
void dispose() {
bloc.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: bloc.hasFile,
initialData: false,
builder: (context, snapshot) {
return snapshot.data ? Text('has a file') : Text("no File");
},
);
}
}
At last you can access BLoC class with your stateless widget as follows
class Homepage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
FlatButton(
child: Text('addFile'),
onPressed: () {
bloc.changeState(true);
}),
FlatButton(
child: Text('deleteFile'),
onPressed: () {
bloc.changeState(false);
})
],
),
body: Child(),
);
}
}
Full example is as below
import 'package:flutter/material.dart';
import 'dart:async';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Homepage(),
);
}
}
class Homepage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
FlatButton(
child: Text('addFile'),
onPressed: () {
bloc.changeState(true);
}),
FlatButton(
child: Text('deleteFile'),
onPressed: () {
bloc.changeState(false);
})
],
),
body: Child(),
);
}
}
class Child extends StatefulWidget {
#override
_ChildState createState() => _ChildState();
}
class _ChildState extends State<Child> {
var hasFile = true;
#override
void dispose() {
bloc.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: bloc.hasFile,
initialData: false,
builder: (context, snapshot) {
return snapshot.data ? Text('has a file') : Text("no File");
},
);
}
}
class Bloc {
final _fileController = StreamController<bool>();
changeState(bool val) {
_fileController.sink.add(val);
}
get hasFile => _fileController.stream;
dispose() {
_fileController.close();
}
}
final bloc = Bloc();

How to call a void function everywhere in my Flutter app using InheritedWidget

I have a main.dart and has a button in center. When user tabs the button it navigate into home.dart page. My home.dart page also has a button on center and when user tabs the button it navigate to details page. The app tree and code is shown below.
I try to implement the "InheritedWidget" in my home.dart so after the home.dart as deep as I go I can call the "void _handleUserInteraction" function using "InheritedWidget". Unluckly I am keep getting error that says:
I/flutter (20715): The getter 'handleOnTap' was called on null.
I/flutter (20715): Receiver: null
I/flutter (20715): Tried calling: handleOnTap
home.dart code:
import 'package:flutter/material.dart';
import 'dart:async';
import 'main.dart';
import 'details.dart';
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Timer timer;
// TODO: 1 - INIT STATE
#override
void initState() {
super.initState();
setState(() {
_initializeTimer();
});
}
// TODO: 3 - INITIALIZE TIMER
void _initializeTimer() {
timer = Timer.periodic(const Duration(minutes: 5), (__) {
_logOutUser();
});
}
// TODO: 4 - LOG OUT USER
void _logOutUser() {
timer.cancel();
Navigator.push(
context, new MaterialPageRoute(builder: (context) => new MyApp()));
}
// TODO: 5 - HANDLE USER INTERACTION
// void _handleUserInteraction([_]) {
void _handleUserInteraction() {
print("+++++++ _handleUserInteraction Header ++++++++");
if (!timer.isActive) {
return;
}
timer.cancel();
_initializeTimer();
print("+++++++ _handleUserInteraction Footer ++++++++");
}
#override
Widget build(BuildContext context) => MaterialApp(
theme: ThemeData(
primarySwatch: Colors.red,
),
home: LoginState(
callback: _handleUserInteraction,
child: Builder(builder: homeScreenBuilder)),
);
}
#override
Widget homeScreenBuilder(BuildContext context) {
Function() _callback = LoginState.of(context).callback;
return GestureDetector(
onTap: _callback,
onDoubleTap: _callback,
onLongPress: _callback,
onTapCancel: _callback,
child: new Scaffold(
appBar: AppBar(
title: Text("HOME PAGE"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'GOTO DETAILS PAGE',
),
new RaisedButton(
child: new Text("Details"),
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new Details()));
})
],
),
),
));
}
class LoginState extends InheritedWidget {
final Widget child;
final Function() callback;
final Key key;
LoginState({#required this.callback, #required this.child, this.key})
: super(key: key);
#override
bool updateShouldNotify(LoginState oldWidget) {
return true;
}
static LoginState of(BuildContext context) =>
context.inheritFromWidgetOfExactType(LoginState);
}
details.dart code:
import 'package:flutter/material.dart';
import 'home.dart';
class Details extends StatefulWidget {
#override
_DetailsState createState() => _DetailsState();
}
class _DetailsState extends State<Details> {
#override
Widget build(BuildContext context) {
Function() _callback = LoginState.of(context).callback;
return GestureDetector(
onTap: _callback,
onDoubleTap: _callback,
onLongPress: _callback,
onTapCancel: _callback,
child: new Scaffold(
appBar: AppBar(
title: Text("Details PAGE"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Every time Tabed it reset the home timer',
),
],
),
),
));
}
}
UPDATE:
I change my home.dart code. The onTap: _callback is working but in details.dart I get same error saying that:
error: - The getter 'callback' was called on null.
The reason why you're getting the error The getter 'callback' was called on null. is because LoginState.of(context) is null.
class _DetailsState extends State<Details> {
#override
Widget build(BuildContext context) {
Function() _callback = LoginState.of(context).callback;
...
}
}
Since you're using InheritedWidget, I assume that you may be attempting to do state management. If so, you can check this guide on implementing app state management. One way of doing this is with the use of provider.
You can try running the sample below. I've based it from the given sample.
main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'dart:async';
import 'details.dart';
void main() {
// https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#changenotifierprovider
runApp(ChangeNotifierProvider(
create: (context) => LoginState(),
child: 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(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
// This allows access to LoginState data if no UI changes needed
// https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#providerof
Provider.of<LoginState>(context, listen: false).initializeTimer();
}
#override
Widget build(BuildContext context) {
// Consumer grants access to LoginState
// https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#consumer
return Consumer<LoginState>(
builder: (context, loginState, child) {
return GestureDetector(
onTap: () => loginState.handleUserInteraction(),
// onDoubleTap: _callback,
// onLongPress: _callback,
// onTapCancel: _callback,
child: new Scaffold(
appBar: AppBar(
title: Text("HOME PAGE"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'GOTO DETAILS PAGE',
),
new RaisedButton(
child: new Text("Details"),
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new Details()));
})
],
),
),
));
},
);
}
}
// https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#changenotifier
class LoginState extends ChangeNotifier {
Timer _timer;
void initializeTimer() {
_timer = Timer.periodic(const Duration(minutes: 5), (__) {
logOutUser();
});
}
void logOutUser() {
_timer.cancel();
}
void handleUserInteraction() {
print("+++++++ _handleUserInteraction Header ++++++++");
if (!_timer.isActive) {
return;
}
_timer.cancel();
initializeTimer();
print("+++++++ _handleUserInteraction Footer ++++++++");
}
}
details.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'main.dart';
class Details extends StatefulWidget {
#override
_DetailsState createState() => _DetailsState();
}
class _DetailsState extends State<Details> {
#override
Widget build(BuildContext context) {
return Consumer<LoginState>(
builder: (context, loginState, child) {
return GestureDetector(
onTap: () => loginState.handleUserInteraction(),
// onDoubleTap: _callback,
// onLongPress: _callback,
// onTapCancel: _callback,
child: new Scaffold(
appBar: AppBar(
title: Text("Details PAGE"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Every time Tabed it reset the home timer',
),
],
),
),
));
},
);
}
}