Flutter - Background Service in Dart (only when app is visible) - service

I need a background service in flutter, that makes very minute a http.get(...)
This service should run in the background, while the app is running. If the app is closed, the background service should stopp also. When the app gets started, the background service should also get started.
I can only find packages, that provide a background service, that also runs, when the app is closed - like this example: https://medium.com/flutter-io/executing-dart-in-the-background-with-flutter-plugins-and-geofencing-2b3e40a1a124
Maybe what I'm looking for is not called "background-service"?
Here is some code, I want to run in this background service/task...
Timer.periodic(Duration(seconds: 60), (Timer t) => checkForUpdates());

I came across the same Problem. Timer.periodic keeps running in the background for an uncontrollable time after leaving the app. My solution is something like this:
class CollectStampsState extends State<CollectStamps> with WidgetsBindingObserver {
Timer timer;
...
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state != AppLifecycleState.resumed) {
timer.cancel();
} else {
if (!timer.isActive) {
timer = Timer.periodic(Duration(seconds: 30), (Timer t) => yourFunction());
}
}
#override
void initState() {
super.initState();
timer = Timer.periodic(Duration(seconds: 30), (Timer t) => yourFunction());
WidgetsBinding.instance.addObserver(this);
}
#override
void dispose() {
timer?.cancel();
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
Widget build(BuildContext context) {
...
}
}
You can also save the AppLifecycleState, if you want to use it in other places, or change the behavior for different AppLifecycleStates. But like this, the timer is only active, when the app is in the foreground. As soon as it's in the Background, the timer is canceled.

Related

Flutter | Stop music when minimised using audioplayers

In my app, I am playing music (local) in a loop, which plays continuously unless the user stops it. I am using audioplayers package.
Future playLoop(String filePath) async {
player.stop();
player = await cache.loop(filePath);
}
Currently, when app is minimised, the music is not getting stoped. The feature I want to implement is that when the app is minimised, it should stop playing music in the background.
Thanks in advance.
Solutions :
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.paused) {
//stop your audio player
}else{
print(state.toString());
}
}
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
There are mainly 4 states for it:
resumed: The application is visible and responding to user input.
inactive: The application is in an inactive state and is not receiving
user input.
paused: The application is not currently visible to the user, not
responding user input, and running in the background.
detached: The application is still hosted on a flutter engine but is
detached from any host views.
The solution above is correct, but some steps are needed before to get it
1 add WidgetsBindingObserver to your class
class AnyClass extends StatefulWidgets {
_AnyClassState createState() => _AnyClassState();
}
class _AnyClassState extends State<AnyClass> with
WidgetsBindingObserver {
Widget build(BuildContext context) {
return ...
}
}
2 Now it will work, we can added the methods inside class
class _AnyClassState extends State<AnyClass> with
WidgetsBindingObserver {
// ADD THIS AppLifecycleState VARIABLE
late AppLifecycleState appLifecycle;
// ADD THIS FUNCTION WITH A AppLifecycleState PARAMETER
didChangeAppLifecycleState(AppLifecycleState state) {
appLifecycle = state;
setStae(() {});
if(state == AppLifecycle.paused) {
// IF YOUT APP IS IN BACKGROUND...
// YOU CAN ADDED THE ACTION HERE
print('My app is in background');
}
}
// CREATE INITSTATE AND DISPOSE METHODS
initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
Widget build(BuildContext context) {
return ...
}
}
NOW IT WILL WORK FINE!

Measuring amount of time the app has been open

I am trying to trigger an event after the app is open for ten minutes. Is there an easy way to do this? I imagine I need to start a timer when the app is first built, but then be able to cancel or pause that timer if the user navigates away from the app somehow.
I have found the screen state library, but that library only listens for the screen turning off and on, and not for events like navigating home or to another app. I'm familiar with WillPopScope, and related to that I found back button interceptor, but my understanding is that only intercepts when the user presses the back button, and not if the user presses home or switches to another app.
Is there some central way for listening to anything that will close or navigate away from the app, or a combination of things to listen to?
Start a Timer when your main method runs:
import 'dart:async';
void main() {
Timer(Duration(minutes: 10), () {
// Handle the event
});
runApp(MyApp());
}
If you want to be able to control the timer, set it up in your root widget and have that widget listen to lifecycle events:
class MyApp extends StatefulWidget {
...
}
class MyAppState extends State<MyApp> with WidgetsBindingObserver {
static const _appTimerDuration = const Duration(minutes: 10);
Timer appTimer;
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
appTimer = Timer(_appTimerDuration, _timerElapsed);
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
appTimer?.cancel();
super.dispose();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
appTimer = Timer(_appTimerDuration, _timerElapsed);
} else {
appTimer?.cancel();
}
}
void _timerElapsed() {
// Handle the event
}
...
}

Flutter : Check AppLifecycle event Suspending

In Flutter docs about AppLifecycle Event, it's have 4 Event .
inactive
paused
resumed
suspending
In 4 event above, i can print AppLifecycle event inactive, paused, resumed, but i can't handle suspending event.
Because i want check if the user kill/destroy the App from task manager. if the user kill/destroy the app , i want show Security Code (like PinCode etc).
How can i handle suspending event ?
class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
AppLifecycleState _appLifecycleState;
FunctionHelper functionHelper = FunctionHelper();
PageController _pageController;
#override
void initState() {
WidgetsBinding.instance.addObserver(this);
_pageController = PageController(initialPage: 0);
super.initState();
}
#override
void didChangeAppLifecycleState(AppLifecycleState appLifecycleState) {
setState(() {
_appLifecycleState = appLifecycleState;
});
print(appLifecycleState);
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
Widget build(BuildContext context) {
if (_appLifecycleState == null) {
return Center(
child: Text('This widget has not observed any lifecycle changes.'),
);
} else {
return Center(
child: Text(
'The most recent lifecycle state this widget observed was: $_appLifecycleState'),
);
}
}
Flutter does not have any API to use onDestroy method of Activity flutter/flutter#21982. During the suspending event the application is suspended momentarily which is equivalent to onStop in Android. When user kills or destroys the App, the onDestroy is triggered in Android therefore it cannot be handled using suspending event.

didChangeAppLifecycleState doesn't work as expected

I hope I understand how didChangeAppLifecycleState worked correctly.
I have page A and page B . When I click the back device button from page B ( Navigator.of(context).pop(); ), I expect didChangeAppLifecycleState in pageA will get called, but it doesn't.
PageA
class _ABCState extends State<ABCrList> with WidgetsBindingObserver {
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
....
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
setState(() {
print(...);
});
}else{
print(state.toString());
}
}
....
This is the initState in pageA. The function used to call backend service.
#override
void initState() {
super.initState();
_bloc.getList(context); // return list and populate to ListView
});
}
The way you're thinking it is Android's way where onResume works, but in Flutter, things don't happen this way.
Generally, this gets called when the system puts the app in the background or returns the app to the foreground.
There are mainly 4 states for it:
resumed: The application is visible and responding to user input.
inactive: The application is in an inactive state and is not receiving user input.
paused: The application is not currently visible to the user, not responding user input, and running in the background.
detached: The application is still hosted on a flutter engine but is detached from any host views.
Edit:
When you're navigating to PageB from PageA, use something like:
Navigator.pushNamed(context, "/pageB").then((flag) {
if (flag) {
// you're back from PageB, perform your function here
setState(() {}); // you may need to call this if you want to update UI
}
});
And from PageB, you'll can use
Navigator.pop(context, true);

Flutter Capture event when app comes to Foreground from triggered Intent

I am trying to pull off some basic stuff here. Scenario: I am checking for GPS status on init() using isLocationServiceEnabled. If the GPS is off, I'm showing a popup that redirects to Location settings using AndroidIntent. If hit back without turning on the GPS, I want to capture the event when my app comes to foreground. I guessed it has to do with the lifecycle and tried like below, nothing gets print on the console
AppLifecycleState _notification;
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
setState(() {
_notification = state;
print('onResumed called 1');
print(_notification);
});
if( state == AppLifecycleState.resumed){
print('onResumed called 2');
}
}
Am I missing something here?
Did you extend class with WidgetsBindingObserver like so:
class _WhateverWidget extends State<WhateverWidget> with WidgetsBindingObserver
and then initialize an instance like so:
#override void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
}
#override void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}