'How to retain the state of the app when navigating to another screen in flutter using riverpod

Good day, guys

I'm new to using Riverpod, I have a counter app that when the FAB button is tapped it increases the counter by 1. This works well using Riverpod ChangeNotifierProvider. The issue I'm currently having is retaining the state of the counter in the second screen when I click on another button that takes the user to the second screen.

Below is my code

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_riverpod_app/counter.dart';
import 'package:flutter_riverpod_app/second_screen.dart';

final counterProvider = ChangeNotifierProvider<Counter>((ref) => Counter());

void main() {
  runApp(ProviderScope(
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        // Center is a layout widget. It takes a single child and positions it
        // in the middle of the parent.
        child: Consumer(builder: (context, watch, _) {
          final count = watch(counterProvider);
          return Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'You have pushed the button this many times:',
              ),
              Text(
                '${count.count}',
                style: Theme.of(context).textTheme.headline4,
              ),
              FlatButton(
                  onPressed: () {
                    Navigator.push(
                        context,
                        MaterialPageRoute(
                            builder: (BuildContext context) => SecondScreen()));
                  },
                  child: Text('Go to second screen'))
            ],
          );
        }),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => context.read(counterProvider).updateCount(),
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

second_screen.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_riverpod_app/counter.dart';

final counterProvider = ChangeNotifierProvider<Counter>((ref) => Counter());

class SecondScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, watch) {
    final counter = watch(counterProvider);
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Screen'),
      ),
      body: Center(
        child: Text('${counter.count}', style: TextStyle(fontSize: 30,),),
      ),
    );
  }
}

counter.dart

import 'package:flutter/foundation.dart';

class Counter extends ChangeNotifier {
  int count = 0;

  updateCount() {
    count++;
    notifyListeners();
  }
}

I don't really know how to get the state of the counter on the second screen, if it was the Provider Package, all I just have to do on the second screen was to use Provider.of<counter>(context, listen: false).counter and it will display the counter.First screenSecond screen where the state isn't retained



Solution 1:[1]

The problem is that you created the Provider twice. You only want to create it once and access it globally.

Remove final counterProvider = ChangeNotifierProvider<Counter>((ref) => Counter()); from your SecondScreen and instead import the counterProvider from your FirstScreen and it will behave as you expect.

Solution 2:[2]

In misc/global.dart

import 'package:hooks_riverpod/hooks_riverpod.dart';
final kCounterProvider = StateProvider((ref) => 0);

In screen/riverpod_screen.dart

import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:flutter_kitchensink/src/misc/global.dart' as global;

class RiverpodScreen extends HookConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Riverpod'),
      ),
      body: Container(
        child: Center(
          child: Text(ref.watch(global.kCounterProvider).toString()),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          ref.read(global.kCounterProvider.notifier).state++;
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

In screen/riverpod2_screen.dart

import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:flutter_kitchensink/src/misc/global.dart' as global;

class Riverpod2Screen extends HookConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Riverpod2'),
      ),
      body: Container(
        child: Center(
          child: Text(ref.watch(global.kCounterProvider).toString()),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          ref.read(global.kCounterProvider.notifier).state++;
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Alex Hartford
Solution 2 exiang