ChangeNotifierProvider isn't listening

1.3k Views Asked by At

I am attempting to share a ChangeNotifierProvider to my main.dart, however the value never gets updated. How it works

  1. main.dart uses ChangeNotifierProvider to get an instance of the class Location()
  2. main.dart routes to the location_login.dart page where a string in Location() class is set.
  3. The instance of Location() should update in main.dart but it DOES NOT.

Here is the main.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(
    ChangeNotifierProvider<Location>.value(    <------ CREATE CHANGENOTIFIERPROVIDER
      value: Location(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Location location = Provider.of<Location>(context, listen: false);  <----- LISTEN TO PROVIDER
    return MultiProvider(
      providers: [
        FutureProvider<List<Report>>(
          create: (context) =>
              Collection<Report>(path: '${location.getLocation}/data/reports')  <----- USE PROVIDER STRING IN PATH
              .getUsers(),
          initialData: [],
        ),
      ],
      child: MaterialApp(
        routes: {
          '/': (context) => LocationLogin(),
          '/login': (context) => LoginScreen(),
          '/home': (context) => HomeScreen(),
        },

        // Theme
        theme: ThemeData(
          fontFamily: 'Nunito',
          bottomAppBarTheme: BottomAppBarTheme(
            color: Colors.black87,
          ),
          // your customizations here
          brightness: Brightness.dark,
          buttonTheme: ButtonThemeData(),
        ),
      ),
    );
  }
}

Here is the location_login.dart

@override
Widget build(BuildContext context) {
Location location = Provider.of<Location>(context, listen: true);
return Scaffold(
  body: TextButton(
          child: Text("Submit",
              style: GoogleFonts.poppins(
                  fontSize: 15.sp, color: Colors.white)),
          onPressed: () {
            location.setLocation('London');              <------- SETTING LOCATION
          }),

    );
  }
}

Here is the location.dart

class Location with ChangeNotifier {
  String place = 'none';

  String get getLocation => place;

  setLocation(String location) {
    place = location;
    notifyListeners();
  }
}

To reiterate, the issue is that when I click the button in the location_login.dart page to set the location to "London"; it does not update the ChangeNotifierProvider with a new instance of the Location() class containing "London". Therefore, I can not update the path in my FurtureProvider. Any ideas of what is going wrong here? I tried to make this as clear as possible but if you don't understand please ask. Thank you

1

There are 1 best solutions below

0
On

I think you have not consume the ChangeNotifierProvider. For me below simple implementation work perfectly.

my main.dart file code is as below...

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

import 'providers/app_provider.dart';
import 'providers/favorites_provider.dart';
import 'providers/comments_provider.dart';
import 'providers/home_provider.dart';
import 'providers/details_provider.dart';
import 'providers/gallery_provider.dart';
import 'providers/chat_provider.dart';
import 'ui/splash.dart';
import 'helper/constants.dart';
import 'ui_user/login.dart';

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => AppProvider()),
        ChangeNotifierProvider(create: (_) => GalleryProvider()),
        ChangeNotifierProvider(create: (_) => CommentsProvider()),
        ChangeNotifierProvider(create: (_) => ChatProvider()),
        ChangeNotifierProvider(create: (_) => HomeProvider()),
        ChangeNotifierProvider(create: (_) => DetailsProvider()),
        ChangeNotifierProvider(create: (_) => FavoritesProvider()),
      ],
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<AppProvider>(
      builder: (BuildContext context, AppProvider appProvider, Widget child) {
        return MaterialApp(
          key: appProvider.key,
          debugShowCheckedModeBanner: false,
          navigatorKey: appProvider.navigatorKey,
          title: Constants.appName,
          theme: appProvider.theme,
          home: appProvider.isLogin ==  "0" ? LoginPage() : Splash(),
        );
      },
    );
  }
}

And my app_provider.dart as below...

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';

import '../helper/constants.dart';

class AppProvider extends ChangeNotifier {
  AppProvider() {
    checkTheme();
  }
  String isLogin = "0";
  ThemeData theme = Constants.lightTheme;
  Key key = UniqueKey();
  GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

  void setKey(value) {
    key = value;
    notifyListeners();
  }

  void setNavigatorKey(value) {
    navigatorKey = value;
    notifyListeners();
  }

  void setTheme(value, c) {
    theme = value;
    SharedPreferences.getInstance().then((prefs) {
      prefs.setString("theme", c).then((val) {
        SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
        SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
          statusBarColor:
              c == "dark" ? Constants.darkPrimary : Constants.lightPrimary,
          statusBarIconBrightness:
              c == "dark" ? Brightness.light : Brightness.dark,
        ));
      });
    });
    notifyListeners();
  }

  ThemeData getTheme(value) {
    return theme;
  }

  Future<ThemeData> checkTheme() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    ThemeData t;
    String r =
        prefs.getString("theme") == null ? "light" : prefs.getString("theme");

    isLogin = prefs.getString("isLogin") == null? "0" : prefs.getString("isLogin");

    if (r == "light") {
      t = Constants.lightTheme;
      setTheme(Constants.lightTheme, "light");
    } else {
      t = Constants.darkTheme;
      setTheme(Constants.darkTheme, "dark");
    }

    return t;
  }
}

This solution is working very well for me. Hope this will help you too...