137

In production mode, is there a way to force a full restart of the application (I am not talking about a hot reload at development time!).

Practical use cases:

  • At initialization process the application detects that there is no network connection. The lack of network connectivity might have prevented a correct start up (e.g. loading of external resource such as JSON files...).

  • During the initial handshaking, new versions of some important resources need to be downloaded (kind of update).

In both use cases, I would like the application to proceed with a full restart, rather than having to build a complex logic at the ApplicationState level.

14 Answers 14

240

You could wrap your whole app into a statefulwidget. And when you want to restart you app, rebuild that statefulwidget with a child that possess a different Key.

This would make you loose the whole state of your app.

import 'package:flutter/material.dart';

void main() {
  runApp(
    RestartWidget(
      child: MaterialApp(),
    ),
  );
}

class RestartWidget extends StatefulWidget {
  RestartWidget({this.child});

  final Widget child;

  static void restartApp(BuildContext context) {
    context.findAncestorStateOfType<_RestartWidgetState>().restartApp();
  }

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

class _RestartWidgetState extends State<RestartWidget> {
  Key key = UniqueKey();

  void restartApp() {
    setState(() {
      key = UniqueKey();
    });
  }

  @override
  Widget build(BuildContext context) {
    return KeyedSubtree(
      key: key,
      child: widget.child,
    );
  }
}

In this example you can reset your app from everywhere using RestartWidget.restartApp(context).

Sign up to request clarification or add additional context in comments.

24 Comments

THIS SHOULD NOT BE THE CORRECT ANSWER as it does not "restart the app" at the OS level. For example, you may need to do this due to the OS memory issues, and to clear it, only completely removing the App from memory and restarting it will help. I have seen examples where this can be done on the android level in the Manifest. Google it.
@JamesGardiner Then what is your solution to this problem?
Is there a way to make all stateful child widgets reset themselves as well? By "reset" I mean create new instances (running the constructor, initstate, etc)? Or do we need to wrap each child widget in its own RestartWidget? If so, is there a way to make it more generic (i.e. get rid of the static method so it can be applied to multiple widgets)? Or better yet, is there a way to truly restart the app, like the Flutter Hot Restart button does?
The above comment regarding Flutter 1.12.1 deprecation needs the line changed to final _RestartWidgetState state = context.findAncestorStateOfType<State<RestartWidget>>(); based on [stackoverflow.com/questions/59448102/…
It worked great for me. But I added navigatorKey in MaterialApp(), and it stop working. Any suggestions? I used navigatorKey for pushing screens without context.
|
57

The flutter_phoenix package is based on Rémi Rousselet's answer, making it even simpler.

void main() {
  runApp(
    Phoenix(
      child: App(),
    ),
  );
}

Then when you need to restart the app, just call:

Phoenix.rebirth(context);

3 Comments

I tried this package but it doesn't work for me the Objects do not reset. Or is it that it doesn't reset the objects?
Didn't work for me, nothing happens when i call rebirth() method
35

I developed the restart_app plugin, with +200 likes in pub.dev, to restart the whole app with native APIs.


Update May 25, 2023:

The package now supports all Android, iOS and Web platforms.

9 Comments

MissingPluginException(No implementation found for method restartApp on channel restart) Is it because of Flutter 2 (I tried to used it on 1.22.6) or something else?
But does it work for iOS devices
Great package. Worked for me for flutter web
Great answer which is working perfectly for me
@hemandroid As version 1.2.0, now it supports iOS as well.
|
21

I just want to add Regarding I have Tried @Remi answer which works great on most of the cases to restart the app. The only problem with the answer is that some things if you are doing Navigation route extensively you probably go to a state which It gives you an error like, The method 'restartApp' was called on null. To resolve this error you have to know the Context and use Navigator.of(context).pop(); multiples times back. For me, the solution is that just go to the initial route. It will inject all the states from a new. Where you want to restart just add this Line.

 Navigator.pushNamedAndRemoveUntil(context,'/',(_) => false);

If you want to only restart a specific widget then the Remi solution is awesome. Thanks for the solution Remi though. It help me understand states in flutter.

5 Comments

After being confronted to the same problem, I must say that this solution is working great for me. Callable from anywhere and all it takes is one line. Keep it simple !
Yes, simple and meets the need.
This is the main solution actually
@Shahryar I cannot thank you enough, it is the best solution
Yep it works out of the box. this one line as it is: Navigator.pushNamedAndRemoveUntil(context,'/',(_) => false);
9

You can also use the runApp(new MyWidget) function to do something similar

This is what this function does:

Inflate the given widget and attach it to the screen.

The widget is given constraints during layout that force it to fill the entire screen. If you wish to align your widget to one side of the screen (e.g., the top), consider using the Align widget. If you wish to center your widget, you can also use the Center widget

Calling runApp again will detach the previous root widget from the screen and attach the given widget in its place. The new widget tree is compared against the previous widget tree and any differences are applied to the underlying render tree, similar to what happens when a StatefulWidget rebuilds after calling State.setState.

https://docs.flutter.io/flutter/widgets/runApp.html

6 Comments

The problem with this is that it may preserve the state
@RémiRousselet Then what is your solution to this problem?
Hey @RémiRousselet, I'm currently using this approach with scoped bloc pattern. Could you help me understand when this may preserve state? Congrats on the I/O announcement.
If you specify a UniqueKey to the widget passed to runApp, that should be fine. The worse is that it makes the widget that wants the refresh knows too much.
This doesn't work. Calling runapp again does exactly nothing.
|
9

Thecnically this is not a restart but it will work for most of the scenarios:

// Remove any route in the stack
Navigator.of(context).popUntil((route) => false);

// Add the first route. Note MyApp() would be your first widget to the app.
Navigator.push(
  context,
  CupertinoPageRoute(builder: (context) => const MyApp()),
);

4 Comments

this looks clean enough
I like this one, this was the simplest and most graceful for my needs. I put this in a timer.
super clean and works
Thank You! This Works like a charm without any plugin. Worked fine for me for fetching "network only" data from DB without showing cached data.
8

So simple package: flutter_restart

dependencies:
flutter_restart: ^0.0.3

to use:

void _restartApp() async {
  FlutterRestart.restartApp();
}

2 Comments

@PålBrattberg i used it in my project and its working fine.
Sorry about that sweeping comment. I run on iOS, Android, Web and macOS, and tried in macOS where it did not work. But for mobile, this is likely to work. I would recommend one of the pure-Flutter answers though, for the simple fact they are likely to work on more platforms.
6

Here is a simplification of the answer by Rémi Rousselet:

Create a global ValueNotifier<UniqueKey>:

/// Write a new UniqueKey to this to restart the app
final ValueNotifier<UniqueKey> appRestartNotifier = ValueNotifier(UniqueKey());

Then in main:

runApp(
  ValueListenableBuilder(
    // Resart the app if the appRestartNotifier changes
    valueListenable: appRestartNotifier,
    builder: (context, key, _) {
      logInfo('Building app');
      return MaterialApp(
        key: key,
        ...

Then to "restart" the app, from anywhere:

appRestartNotifier.value = UniqueKey();

Although note that as others have observed, this is not a "hard restart" -- it just basically rebuilds the entire widget tree. Which will probably do nothing more than you would get from changing the current route (depending on the state management and routing mechanism of your app).

2 Comments

Thanks! This solution works as expected. We can improve this by removing the key in MaterialApp. Doing this will not restart the app.
@DharamBudh I think the key is actually needed. Sometimes Flutter diffs the current widget tree and the new widget tree, and if it determines that they are structurally the same, it assumes that there were no UI updates. Adding a key forces the layout engine to throw away the old widget tree.
5

I have found Hossein's restart_app package also pretty useful for native restarts (not only on Flutter level).

To everyone having the MissingPluginException error, just reinstall the app again on the device, means that hot reload won't work. The app has native methods which need to compiled in the Android/iOS App.

2 Comments

Thanks, man. I think the package link in your answer has a problem. The correct link is: pub.dev/packages/restart_app
Just as an update, the package is updated to v1.2.0 and now it supports iOS as well.
4

I wanted to restart my app after logout. so I used https://pub.dev/packages/flutter_phoenix (flutter phoenix). It worked for me.

  1. Install flutter_phoenix by running this command on your terminal inside your flutter app directory. $ flutter pub add flutter_phoenix
  2. Import it inside your "main.dart".
  3. Wrap your root widget inside Phoenix.
     runApp(
    Phoenix(
      child: MyApp()
  ));

  1. Now you can call this wherever you want to restart your app :- Phoenix.rebirth(context)

Note: flutter_phoenix does not restart the app on OS level, it only restarts the app on app level.

Comments

1

I tried the above suggested methods and none of them worked and i was using getx. so i ended up modified the accepted answer with a delay as a workaround and it works now.

   class RestartAppWidget extends StatefulWidget {
  RestartAppWidget({this.child});

  final Widget child;

  static void restartApp(BuildContext context) {
    context.findAncestorStateOfType<_RestartAppWidgetState>().restartApp();
  }

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

class _RestartAppWidgetState extends State<RestartAppWidget> {
  bool restarting = false;

  void restartApp() async {
    restarting = true;   // restart variable is set to true
    setState(() {});
    Future.delayed(Duration(milliseconds: 300)).then((value) {
      setState(() {
        restarting = false; //restart variable is set to false
      });
    });
    // setState(() {
    //   key = UniqueKey();
    // });
  }

  @override
  Widget build(BuildContext context) {
    if (restarting) {
      return SizedBox();   //an empty Sizedbox is displayed for 300 milliseconds you can add a loader if you want
    }
    return SizedBox(
      child: widget.child,
    );
  }
}`

wrap the root widget with RestartAppWidget

  runApp(RestartAppWidget(
      child: MyApp(),
    ))

you can use this code to restart the app at flutter level

RestartAppWidget.restartApp(Get.context);

2 Comments

You just needed to call 'Get.reset()' before calling the restartApp().
This seems a far better approach, nice
1

The code bellow worked for me by navigating to the stateful widget which is called in the void main function located in main.dart, in my case that widget is called MyApp.

Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context)=>MyApp()), (route) => false);

Comments

0

Follow the steps-

  1. Go to your terminal and type in the following:
flutter pub add flutter_restart

This will update some dependencies in pubspec.yaml file.

  1. Import the following package in whichever file you want to implement the restart code-
import 'package:flutter_restart/flutter_restart.dart';
  1. Create a void function
void _restartApp() async {
  await FlutterRestart.restartApp();
}
  1. Write this wherever you want to start the app-
_restartApp();

Comments

0

There is another way no one mentioned

were we can add entryPoint method inside main and for restart just call that method it's even more useful if you wanna pass env for example here is the code

void main() async {
  await entryPoint(Environment.dev);
}

and to restart call this method from anywhere will restart the entire app

// restart
await entryPoint(Environment.dev)

this is more helpful if you have configurations like sentry and you wanna update it based on [env] for example where sentry configuration before runApp.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.