I am new to Flutter and I am trying to save the value of "counter" on first_screen when I navigate to second_screen and after that I want to save the value of "secondCounter" on second_screen when I navigate to first_screen. The "counter" and "secondCounter" value resets to 0 when I navigate between the two screens but I want to save the values of them. My code is as follows :

main.dart :-

import 'package:flutter/material.dart';
import 'package:provider_practice/screens/first_screen.dart';
import 'package:provider_practice/screens/second_screen.dart';

void main() {
  runApp(MaterialApp(
    home: FirstScreen(),

    routes: {
      "/first" : (context) => FirstScreen(),
      "/second" : (context) => SecondScreen(),
    },
  ));
}

first_screen :-

import 'package:flutter/material.dart';

class FirstScreen extends StatefulWidget {
  @override
  _FirstScreenState createState() => _FirstScreenState();
}

class _FirstScreenState extends State<FirstScreen> {

  int counter = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("First Screen"),
      ),

      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text("You pressed the button $counter times."),
              SizedBox(height: 20),
              RaisedButton(
                onPressed: () {
                  setState(() {
                    counter++;
                  });
                },
                child: Text("Click Me"),
              ),
              SizedBox(height: 20),
              RaisedButton(
                onPressed: () {
                  Navigator.pushNamed(context, "/second");
                },
                child: Text("Go to Second"),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

second_screen.dart :-

import 'package:flutter/material.dart';

class SecondScreen extends StatefulWidget {
  @override
  _SecondScreenState createState() => _SecondScreenState();
}

class _SecondScreenState extends State<SecondScreen> {

  int secondCounter = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Second Screen"),
       ),

      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text("You pressed the button $secondCounter times."),
              SizedBox(height: 20),
              RaisedButton(
                onPressed: () {
                  setState(() {
                    secondCounter++;
                  });
                },
                child: Text("Click Me"),
              ),
              SizedBox(height: 20),
              RaisedButton(
                onPressed: () {
                  Navigator.pushNamed(context, "/first");
                  //Navigator.pop(context);
                },
                child: Text("Go to First"),
              ),
            ],
          ),
        ),
      ),
    );
  }
}


Solution 1: Hady

This is easy to implement and there are a few ways you can do it.

One way is to pass it in as a parameter. If you add the counter variable to be inside of the FirstScreen/SecondScreen widgets, you can then add them to the constructor.

Example:

class FirstScreen extends StatefulWidget {
  int counter;

  FirstScreen(counter);

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

Then in your state's body you would change the text to Text("You pressed the button ${widget.counter} times.") and the setState function to setState(() {widget.counter++;});

You would do the same in the second widget making a parameter called counter or whatever you want and then make a constructor. You can also make it required or set it to have a default of 0 if it is not passed through.

Finally, to pass it through to the second widget you can just use Navigator.push(context, SecondScreen(widget.counter) and vice versa. This however, won't let you use named routes.

Another approach is to use arguments and named routes. I think this will suit your use case better.

In both of your screens where you navigate, just add an arguments parameter and pass in the counter Navigator.pushNamed(context, 'routePath', arguments: counter);. (P.S. You don't have to name the counters as firstCounter and secondCounter, they can both be called counter since they are in different widgets). Then just add to both widgets counter = ModalRoute.of(context).arguments. You also don't need to wrap your counter value in curly braces ({}). In the vide he needed the data as a map so he did that, but you just want a number. Hope this helps.

Here is a video I found which explains how to pass arguments in named routes if you find the text confusing. For context, this is a video series teaching Flutter and the app he is currently building is a world time app. Video Link.

If you are interested in the entire course here is the Video Playlist


Solution 2: Hady

I am not sure if you specifically you need it to reset when the app relaunches or not but if it is fine if the value is preserved when you relaunch the app then here are a few options. Either way, you can reset the value when the app launches manually by setting it back to 0.

The first and simplest way is to use the answer in this comment. If you have both widgets in an IndexedStack (read more here) and then have the button change the stack index that would work but you would lose the benefit of page transition animations and this is a less performant option as your app grows because flutter has to run both widgets at the same time even if one isn't being used.

A second more performant way you can do this is through the Shared Preferences package. This would save it to the disk so you would need to reset it every time you launch the app if you want it to be 0 every time you open the app.

A third way is to use an external database such as Firebase. Firebase offers both their "Realtime Database" and their newer "Cloud Firestore" as well as their authentication services all for free so it might be an option you want to look into for building apps in the future. I would recommend Firestore over the real time database because it is newer and I prefer it personally. This option would also need you to reset the counter when launching the app but that shouldn't be too big of a problem.

Another way you can do this (this won't preserve state when relaunching the app) is to use the Provider Package. This package was endorsed by Flutter and is the recommended way to manage state. If you add a provider at the root of your app then it will be preserved and it can store both the first and second counter for you. Provider has a bit of a learning curve so I would recommend you look into it a bit.

Here are two videos which helped me get started with Provider:

  1. https://youtu.be/O71rYKcxUgA
  2. https://youtu.be/MkFjtCov62g

I'd recommend you watch them both as they are by the same person and one is an introduction to what Provider is and the other shows you how to use it. The second video has a similar example to your use case but I'd recommend you still watch both.

Hope this helps. Please let me know if this answered your question or if you need any more help or clarification please let me know.