7

How can I monitor the life cycle states of the app from a particular page using HookWidget the way you can with a Stateful widget?

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

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

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    if (state == AppLifecycleState.paused) {
         ...
    }
    if (state == AppLifecycleState.resumed) {
        ...
    }
    if (state == AppLifecycleState.detached) {
       ...
    }
  }
Gerry
  • 1,159
  • 1
  • 14
  • 29

4 Answers4

7

First make a class:

class MyObserver implements WidgetsBindingObserver {
}

Then create it and register it with:

Widget build(BuildContext) {
  useEffect(() {
    final observer = MyObserver();
    WidgetsBinding.instance.addObserver(observer);
    return () => WidgetsBinding.instance.removeObserver(observer);
  }, const []);

  ...
}
Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432
  • 1
    Hey, just wondering, how am I able to then access provider in my didChangeAppLifecycleState? since useProvider, `useContext` can only be called from the build method of HookWidget? – Frederick Mfinanga Dec 11 '20 at 04:56
  • @FrederickMfinanga Create the `MyObserver` class, since it's implemented the `WidgetsBindingObserver` class, you must override 10 of its methods. `didChangeAppLifecycleState` method is one of them. – Almett Apr 17 '22 at 15:19
  • @rémi-rousselet I guess it is better to extend `WidgetsBindingObserver` than implementing it as I have to override all 10 methods if I implement. – Praveena Jan 31 '23 at 04:39
4

Flutter hooks is shipped with an inbuilt didchangeapplifecycle access it as follows

    final appLifecycleState = useAppLifecycleState();

    useEffect(() {
      print("current app state");
      print(appLifecycleState);
      if (appLifecycleState == AppLifecycleState.paused || appLifecycleState == AppLifecycleState.inactive) {
        //...
      } else if (appLifecycleState == AppLifecycleState.resumed) {
        //...
      }
      return null;
    }, [appLifecycleState]);
Shei
  • 393
  • 4
  • 15
3

In the docs here search for "ways to create a hook". You'll see there are 2 ways of creating a hook, using a function or using a class. You are going for the "using a class" one. Then use initHook override as your initState and dispose works the same. Thats how I implemented it on my end.

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

useWidgetLifecycleObserver(BuildContext context) {
  return use(const _WidgetObserver());
}

class _WidgetObserver extends Hook<void> {
  const _WidgetObserver();

  @override
  HookState<void, Hook<void>> createState() {
    return _WidgetObserverState();
  }
}

class _WidgetObserverState extends HookState<void, _WidgetObserver> with WidgetsBindingObserver {
  @override
  void build(BuildContext context) {}

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

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

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    print("app state now is $state");
    super.didChangeAppLifecycleState(state);
  }
}

Then

class Root extends HookWidget {

  @override
  Widget build(BuildContext context) {
    useWidgetLifecycleObserver(context);
A K
  • 788
  • 6
  • 17
Philip Kalela
  • 125
  • 13
  • 1
    Is there a way to access context inside didChangeAppLifecycleState? I'm using provider and would like to call a function from a service I expose. – Frederick Mfinanga Dec 29 '20 at 03:05
0

I've just had to deal with the same problem. And here is my solution using custom hooks:

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

AppLifecycleState useAppLifecycleState() {
  return use(const _LifeCycleState());
}

class _LifeCycleState extends Hook<AppLifecycleState> {
  const _LifeCycleState();

  @override
  __LifeCycleState createState() => __LifeCycleState();
}

class __LifeCycleState extends HookState<AppLifecycleState, _LifeCycleState>
    with WidgetsBindingObserver {
  AppLifecycleState _theState;

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

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    setState(() {
      _theState = state;
    });
  }

  @override
  AppLifecycleState build(BuildContext context) {
    return _theState;
  }

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

And in the HookWidget that you want to access the app lifecycle state use the useEffect :

final appLifecycleState = useAppLifecycleState();

useEffect(() {
  print("current app state");
  print(appLifecycleState);
  if (appLifecycleState == AppLifecycleState.paused ||
      appLifecycleState == AppLifecycleState.inactive) {
    //...
  } else if (appLifecycleState == AppLifecycleState.resumed) {
    //...
  }
  return null;
}, [appLifecycleState]);
SalahAdDin
  • 2,023
  • 25
  • 51
  • The build method is not calling on real iPhone devices as the app is in background. So my code for inactive is not called – Diego Garcia Apr 24 '21 at 15:57