onResume() and onPause() for widgets on Flutter
There is an abstract class caller WidgetsBindingObserver
https://docs.flutter.io/flutter/widgets/WidgetsBindingObserver-class.html
in
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
setState(() {
_notification = state;
});
}
there is the "state", can be manage as
switch(state) {
case AppLifecycleState.resumed:
// Handle this case
break;
case AppLifecycleState.inactive:
// Handle this case
break;
case AppLifecycleState.paused:
// Handle this case
break;
case AppLifecycleState.suspending:
// Handle this case
break;
}
The most common case where you'd want to do this is if you have an animation running and you don't want to consume resources in the background. In that case, you should extend your State
with TickerProviderStateMixin
and use your State
as the vsync
argument for the AnimationController
. Flutter will take care of only calling the animation controller's listeners when your State
is visible.
If you want the State
s that live in your PageRoute
to be disposed when the PageRoute
is obscured by other content, you can pass a maintainState
argument of false
to your PageRoute
constructor. If you do this, your State
will reset itself (and its children) when it's hidden and will have to re-construct itself in initState
using the properties passed in as constructor arguments to its widget
. You can use a model or controller class, or PageStorage
, to hold the user's progress information if you don't want a complete reset.
Here is a sample app that demonstrates these concepts.
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
onGenerateRoute: (RouteSettings settings) {
if (settings.name == '/') {
return new MaterialPageRoute<Null>(
settings: settings,
builder: (_) => new MyApp(),
maintainState: false,
);
}
return null;
}
));
}
class MyApp extends StatefulWidget {
MyAppState createState() => new MyAppState();
}
class MyAppState extends State<MyApp> with TickerProviderStateMixin {
AnimationController _controller;
@override
void initState() {
print("initState was called");
_controller = new AnimationController(vsync: this)
..repeat(min: 0.0, max: 1.0, period: const Duration(seconds: 1))
..addListener(() {
print('animation value ${_controller.value}');
});
super.initState();
}
@override
void dispose() {
print("dispose was called");
_controller.dispose();
super.dispose();
}
int _counter = 0;
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('home screen')
),
body: new Center(
child: new RaisedButton(
onPressed: () {
setState(() {
_counter++;
});
},
child: new Text('Button pressed $_counter times'),
),
),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.remove_red_eye),
onPressed: () {
Navigator.push(context, new MaterialPageRoute(
builder: (BuildContext context) {
return new MySecondPage(counter: _counter);
},
));
},
),
);
}
}
class MySecondPage extends StatelessWidget {
MySecondPage({ this.counter });
final int counter;
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Certificate of achievement'),
),
body: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
new Icon(Icons.developer_mode, size: 200.0),
new Text(
'Congrats, you clicked $counter times.',
style: Theme.of(context).textTheme.title,
textAlign: TextAlign.center,
),
new Text(
'All your progress has now been lost.',
style: Theme.of(context).textTheme.subhead,
textAlign: TextAlign.center,
),
],
),
);
}
}
This is a full example demonstrating how to properly handle things, to test this, press home button and resume the app, you shall see didChangeAppLifecycleState
is getting called.
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
// Add the observer.
WidgetsBinding.instance!.addObserver(this);
}
@override
void dispose() {
// Remove the observer
WidgetsBinding.instance!.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
// These are the callbacks
switch (state) {
case AppLifecycleState.resumed:
// widget is resumed
break;
case AppLifecycleState.inactive:
// widget is inactive
break;
case AppLifecycleState.paused:
// widget is paused
break;
case AppLifecycleState.detached:
// widget is detached
break;
}
}
@override
Widget build(BuildContext context) => Scaffold();
}