Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter app restoration; how to save the app state when the activity is killed by the system?

I'm an android developer and I want to switch to flutter. I love the hot reload feature that allows for faster development time. The only thing that prevents me from switching so far is that flutter lacks the option to save the app state when the activity is killed. In native android the option is provided for free (onSaveInstanceState(Bundle savedInstanceState)). So my question is, how can I implement the same feature in Flutter?

like image 329
Toni Joe Avatar asked Nov 25 '19 22:11

Toni Joe


People also ask

Why is Exit 0 not preferred for closing an app Flutter?

Close Android App With Code: exit(0) : This command also works but it is not recommended because it terminates the Dart VM process immediately and users may think that the app got crashed.

What is state restoration Flutter?

Flutter(from version 1.22 onwards) gives out of the box support for state restoration now. You can add your restorable properties which will be automatically restored when the application comes into active state after the OS kills it in the background.


3 Answers

Beginning with Flutter 1.22 (which is now in stable), you can make use of RestorationMixin. Here's a full example:

void main() {
  runApp(
    RootRestorationScope(
      restorationId: 'root',
      child: MaterialApp(home: HomePage()),
    ),
  );
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with RestorationMixin {
  final RestorableInt _counter = RestorableInt(0);

  @override
  String get restorationId => 'HomePage';

  @override
  void restoreState(RestorationBucket oldBucket, bool initialRestore) {
    registerForRestoration(_counter, 'counter');
  }

  @override
  void dispose() {
    _counter.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          child: Text('${_counter.value}'),
          onPressed: () => setState(() => ++_counter.value),
        ),
      ),
    );
  }
}

How to test:

  • Go to your device Settings - Developer Options and turn on Don't keep activities.

enter image description here

  • Now run the app on your Android device, tap the Counters button and hit the home button to force Android to exit your app.

  • Open the app again and you should see the counter value persist.

like image 143
CopsOnRoad Avatar answered Oct 31 '22 05:10

CopsOnRoad


You need to use a plugin and method channels in order to know when to persist things, and when to restore things. For that, you can use the following library:

https://github.com/littlerobots/flutter-native-state

It lets you send your state into a Bundle on the Android side, and communicates restored state back to Flutter through method channel.

like image 24
EpicPandaForce Avatar answered Oct 31 '22 05:10

EpicPandaForce


Thanks to @CopsOnRoad, points below are related to his answer.

  1. We should use RootRestorationScope instead of RestorationScope

like this...

void main() {
      runApp(
          RootRestorationScope( // <--fix
          restorationId: 'root',
          child: MaterialApp(home: HomePage()),
        ),
      );
    }
  1. also RestorationMixin has generic: RestorationMixin<HomePage> - not necessary, but if you want to declare your HomeRestorationMixin later, and if you want to make correct signature in didUpdateWidget(HomePage widget) method...

  2. also we should manually run dispose() for every property of the State:

so it will be

class _HomePageState extends State<HomePage> with 
  RestorationMixin<HomePage> { // <-- optional
  ...
  @override
  void dispose() {
    _counter.dispose(); // <-- recommended
    super.dispose();
  }
}
like image 32
Vladimir.Shramov Avatar answered Oct 31 '22 06:10

Vladimir.Shramov