Flutter: Update Widgets On Resume?

DartFlutter

Dart Problem Overview


In Flutter, is there a way to update widgets when the user leaves the app and come right back to it? My app is time based, and it would be helpful to update the time as soon as it can.

Dart Solutions


Solution 1 - Dart

You can listen to lifecycle events by doing this for example :

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';

class LifecycleEventHandler extends WidgetsBindingObserver {
  final AsyncCallback resumeCallBack;
  final AsyncCallback suspendingCallBack;

  LifecycleEventHandler({
    this.resumeCallBack,
    this.suspendingCallBack,
  });

  @override
  Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
    switch (state) {
      case AppLifecycleState.resumed:
        if (resumeCallBack != null) {
          await resumeCallBack();
        }
        break;
      case AppLifecycleState.inactive:
      case AppLifecycleState.paused:
      case AppLifecycleState.detached:
        if (suspendingCallBack != null) {
          await suspendingCallBack();
        }
        break;
    }
  }
}



class AppWidgetState extends State<AppWidget> {
  void initState() {
    super.initState();

    WidgetsBinding.instance.addObserver(
      LifecycleEventHandler(resumeCallBack: () async => setState(() {
        // do something
      }))
    );
  }
  ...
}

Solution 2 - Dart

Using system Channel:

import 'package:flutter/services.dart';

SystemChannels.lifecycle.setMessageHandler((msg){
  debugPrint('SystemChannels> $msg');
  if(msg==AppLifecycleState.resumed.toString())setState((){});
});

`

Solution 3 - Dart

Simple way:

import 'package:flutter/services.dart';

handleAppLifecycleState() {
    AppLifecycleState _lastLifecyleState;
    SystemChannels.lifecycle.setMessageHandler((msg) {
      
     print('SystemChannels> $msg');

        switch (msg) {
          case "AppLifecycleState.paused":
            _lastLifecyleState = AppLifecycleState.paused;
            break;
          case "AppLifecycleState.inactive":
            _lastLifecyleState = AppLifecycleState.inactive;
            break;
          case "AppLifecycleState.resumed":
            _lastLifecyleState = AppLifecycleState.resumed;
            break;
          case "AppLifecycleState.suspending":
            _lastLifecyleState = AppLifecycleState.suspending;
            break;
          default:
        }
    });
  }

just add handleAppLifecycleState() in your init()

OR

class AppLifecycleReactor extends StatefulWidget {
      const AppLifecycleReactor({ Key key }) : super(key: key);
    
      @override
      _AppLifecycleReactorState createState() => _AppLifecycleReactorState();
    }
    
    class _AppLifecycleReactorState extends State<AppLifecycleReactor> with WidgetsBindingObserver {
      @override
      void initState() {
        super.initState();
        WidgetsBinding.instance.addObserver(this);
      }
    
      @override
      void dispose() {
        WidgetsBinding.instance.removeObserver(this);
        super.dispose();
      }
    
      AppLifecycleState _notification;
    
      @override
      void didChangeAppLifecycleState(AppLifecycleState state) {
        setState(() { _notification = state; });
      }
    
      @override
      Widget build(BuildContext context) {
        return Text('Last notification: $_notification');
      }
    }

For more details you refer documentation

Solution 4 - Dart

For deeply testing, I think the results are worth for read. If you are curious about which method you should use, just read the below: (Tested on Android)

There are three methods for LifeCycle solution.

  1. WidgetsBindingObserver
  2. SystemChannels.lifecycle
  3. flutter-android-lifecycle-plugin

The main difference between WidgetsBindingObserver and SystemChannels.lifecycle is that WidgetsBindingObserver have more capables If you have a bunch of widgets that need to listen LifeCycle. SystemChannels is more low layer, and used by WidgetsBindingObserver.

After several testing, If you use SystemChannels after runApp, and home widget mixin with WidgetsBindingObserver, home widget would be failed, because SystemChannels.lifecycle.setMessageHandler override the home's method.

So If you want to use a global, single method, go for SystemChannels.lifecycle, others for WidgetsBindingObserver.

And what about the third method? This is only for Android, and If you must bind your method before runApp, this is the only way to go.

Solution 5 - Dart

import 'package:flutter/material.dart';

abstract class LifecycleWatcherState<T extends StatefulWidget> extends State<T>
    with WidgetsBindingObserver {
  @override
  Widget build(BuildContext context) {
    return null;
  }

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      case AppLifecycleState.resumed:
        onResumed();
        break;
      case AppLifecycleState.inactive:
        onPaused();
        break;
      case AppLifecycleState.paused:
        onInactive();
        break;
      case AppLifecycleState.detached:
        onDetached();
        break;
    }
  }

  void onResumed();
  void onPaused();
  void onInactive();
  void onDetached();
}

Example

class ExampleStatefulWidget extends StatefulWidget {
  @override
  _ExampleStatefulWidgetState createState() => _ExampleStatefulWidgetState();
}

class _ExampleStatefulWidgetState
    extends LifecycleWatcherState<ExampleStatefulWidget> {
  @override
  Widget build(BuildContext context) {
    return Container();
  }

  @override
  void onDetached() {
    
  }

  @override
  void onInactive() {
    
  }

  @override
  void onPaused() {
    
  }

  @override
  void onResumed() {
    
  }
}

Solution 6 - Dart

Here’s an example of how to observe the lifecycle status of the containing activity (Flutter for Android developers):

import 'package:flutter/widgets.dart';

class LifecycleWatcher extends StatefulWidget {
  @override
  _LifecycleWatcherState createState() => _LifecycleWatcherState();
}

class _LifecycleWatcherState extends State<LifecycleWatcher> with WidgetsBindingObserver {
  AppLifecycleState _lastLifecycleState;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    setState(() {
      _lastLifecycleState = state;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (_lastLifecycleState == null)
      return Text('This widget has not observed any lifecycle changes.', textDirection: TextDirection.ltr);

    return Text('The most recent lifecycle state this widget observed was: $_lastLifecycleState.',
        textDirection: TextDirection.ltr);
  }
}

void main() {
  runApp(Center(child: LifecycleWatcher()));
}

Solution 7 - Dart

Solutions implemented for detecting onResume event using "WidgetsBindingObserver" OR "SystemChannels.lifecycle" works only when App is gone in background completely like during lock screen event or during switching to another app. It will not work if user navigate between screens of app. If you want to detect onResume event even when switching between different screens of same app then use visibility_detector library from here : https://pub.dev/packages/visibility_detector

  @override
Widget build(BuildContext context) {
  return VisibilityDetector(
    key: Key('my-widget-key'),
    onVisibilityChanged: (visibilityInfo) {
      num visiblePercentage = visibilityInfo.visibleFraction * 100;
      debugPrint(
          'Widget ${visibilityInfo.key} is ${visiblePercentage}% visible');
      if(visiblePercentage == 100){
                debugPrint("Resumed !");
              }
    },
    child: someOtherWidget,
  );
}

Solution 8 - Dart

If you want to execute onResume method but only in one page you can add this in your page:

var lifecycleEventHandler;

@override
  void initState() {
    super.initState();

    ///To listen onResume method
    lifecycleEventHandler = LifecycleEventHandler(
        resumeCallBack: () async {
          //do something
        }
    );
    WidgetsBinding.instance.addObserver(lifecycleEventHandler);
  }

@override
  void dispose() {
    if(lifecycleEventHandler != null)
      WidgetsBinding.instance.removeObserver(lifecycleEventHandler);

    super.dispose();
  }

and having LifecycleEventHandler class as the first answer of this post:

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';

class LifecycleEventHandler extends WidgetsBindingObserver {
  final AsyncCallback resumeCallBack;
  final AsyncCallback suspendingCallBack;

  LifecycleEventHandler({
    this.resumeCallBack,
    this.suspendingCallBack,
  });

  @override
  Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
    switch (state) {
      case AppLifecycleState.resumed:
        if (resumeCallBack != null) {
          await resumeCallBack();
        }
        break;
      case AppLifecycleState.inactive:
      case AppLifecycleState.paused:
      case AppLifecycleState.detached:
        if (suspendingCallBack != null) {
          await suspendingCallBack();
        }
        break;
    }
  }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoshView Question on Stackoverflow
Solution 1 - DartGünter ZöchbauerView Answer on Stackoverflow
Solution 2 - DartUpaJahView Answer on Stackoverflow
Solution 3 - DartRahul MahadikView Answer on Stackoverflow
Solution 4 - DartTokenyetView Answer on Stackoverflow
Solution 5 - Dartkarzan kamalView Answer on Stackoverflow
Solution 6 - DartIgor BokovView Answer on Stackoverflow
Solution 7 - Dartuser3930098View Answer on Stackoverflow
Solution 8 - DartÁlvaro AgüeroView Answer on Stackoverflow