flutterflutter-provider

The values for lat,lng returned by the provider are received as null in another page


I am obtaining latitude and longitude using the location. The code below is what I have set up. The reason I used a Provider here is that the latitude and longitude values change whenever the location changes.

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

class MapProvider extends ChangeNotifier {
  double? lat;
  double? lng;
  Location location = Location();
  late bool _serviceEnabled;
  late PermissionStatus _permissionGranted;


  locateMe() async {
    _serviceEnabled = await location.serviceEnabled();
    if (!_serviceEnabled) {
      _serviceEnabled = await location.requestService();
      if (!_serviceEnabled) {
        return;
      }
    }

    _permissionGranted = await location.hasPermission();
    if (_permissionGranted == PermissionStatus.denied) {
      _permissionGranted = await location.requestPermission();
      if (_permissionGranted != PermissionStatus.granted) {
        return;
      }
    }
    await location.getLocation().then((res) {
      lat = res.latitude;
      lng = res.longitude;
      print('provider $lat long : $lng');
      notifyListeners();
    });
  }
}

The latitude (lat) and longitude (lng) values are well returned from the provider I created. However, when I try to retrieve these values on the home page, it only returns null.

import 'package:capstone_flutter/provider/map_provider.dart';
import 'package:flutter/material.dart';
import 'package:flutter_naver_map/flutter_naver_map.dart';
import 'package:provider/provider.dart';

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Center(
      child: SizedBox(
        width: MediaQuery.of(context).size.width * 1,
        height: MediaQuery.of(context).size.height * 1,
        child: Stack(
          children: [
            Consumer<MapProvider> (
              builder: (context, naverMapProvider, child) {
                print(
                    'return lat: ${naverMapProvider.lat}, lng: ${naverMapProvider.lng}');
                if (naverMapProvider.lat == null ||
                    naverMapProvider.lng == null) {
                  return CircularProgressIndicator();
                }
                return NaverMap(
                  options: NaverMapViewOptions(
                    initialCameraPosition: NCameraPosition(
                      target:
                          NLatLng(naverMapProvider.lat!, naverMapProvider.lng!),
                      zoom: 15,
                      bearing: 0,
                      tilt: 0,
                    ),
                  ),
                  onMapReady: (controller) {
                    print("naver loading");
                  },
                );
              },
            ),
            Positioned(
              bottom: 20,
              left: 10,
              child: Container(
                decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(25),
                    border: Border.all(
                        width: 2, color: Colors.black.withOpacity(0.3))),
                child: TextButton(
                  onPressed: () {
                    Navigator.pushNamed(context, '/store_list');
                  },
                  child: Row(
                    children: [
                      Icon(
                        Icons.list,
                        color: Color(0xFFBB0000),
                      ),
                      Text(
                        "list",
                        style: TextStyle(color: Colors.black),
                      ),
                    ],
                  ),
                ),
              ),
            ),
            Positioned(
                bottom: 20,
                right: 10,
                child: Container(
                  decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(100),
                      border: Border.all(
                          width: 2, color: Colors.black.withOpacity(0.3))),
                  child: Padding(
                    padding: const EdgeInsets.all(8),
                    child: (Icon(
                      Icons.my_location_outlined,
                      size: 30,
                      color: Colors.black.withOpacity(0.6),
                    )),
                  ),
                )),
            Padding(
              padding: const EdgeInsets.all(10),
              child: Container(
                width: 360,
                height: 44,
                decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(30),
                    border: Border.all(
                      width: 2,
                      color: Colors.black.withOpacity(0.3),
                    )),
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Row(
                    children: [
                      Icon(
                        Icons.location_on_outlined,
                        color: Color(0xFFBB0000),
                      ),
                      SizedBox(
                        width: 5,
                      ),
                      Text("address")
                    ],
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

The locateMe() method is called when logging in and pressing a button. below code is LoginPage code.

import 'package:capstone_flutter/components/define_color.dart';
import 'package:capstone_flutter/mvvm/token_view_model.dart';
import 'package:capstone_flutter/provider/map_provider.dart';
import 'package:capstone_flutter/service/api_client.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class LoginPage extends StatefulWidget {
  const LoginPage({super.key});

  @override
  State<LoginPage> createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  bool isChecked = false;

  final TextEditingController idController = TextEditingController();
  final TextEditingController passwordController = TextEditingController();
  final MapProvider naverMapModelRepository = MapProvider();

  final ApiClient _apiClient = ApiClient();

  bool _showPassword = false;

  @override
  Widget build(BuildContext context) {
    TokenViewModel tokenViewModel =
        Provider.of<TokenViewModel>(context, listen: false);

    Future<void> login() async {
      dynamic res = await _apiClient.login(
        idController.text,
        passwordController.text,
      );
      print(res);

    
      if (idController.text.isEmpty || passwordController.text.isEmpty) {
        return null;
      }

      if (res['isSuccess'] == true) {
        tokenViewModel.updateAccessToken(res['data']['accessToken']);
        tokenViewModel.updateRefreshToken(res['data']['refreshToken']);
        await naverMapModelRepository.locateMe();  //I Use locateMe
        Navigator.pushNamed(context, '/login_success');
      } else {
        print(res);
      }
    }

    return Scaffold(
        appBar: AppBar(),
        body: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const SizedBox(
              height: 140,
            ),
            const Center(
              child: Text(
                'jatduree',
                style: TextStyle(
                  fontSize: 30,
                  fontWeight: FontWeight.w900,
                ),
              ),
            ),
            const SizedBox(
              height: 50,
            ),
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16.0),
              child: idTextFormField(),
            ),
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: passwordTextFormField(),
            ),
            Row(
              children: [
                Checkbox(
                  value: isChecked,
                  onChanged: (bool) {
                    setState(() {
                      isChecked = !isChecked;
                    });
                  },
                ),
                const Text(
                  "store ID",
                ),
                const SizedBox(
                  width: 100,
                ),
                TextButton(
                    onPressed: () {
                      Navigator.pushNamed(context, '/find_id_password');
                    },
                    child: Text(
                      "find Id and Password",
                      style: TextStyle(color: Color(0xFFBB0000)),
                    ))
              ],
            ),
            const SizedBox(
              height: 24,
            ),
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: GestureDetector(
                onTap: login,
                child: Container(
                  width: 500,
                  height: 60,
                  decoration: BoxDecoration(
                    color: Color(DefineColor.loginBtnColor),
                    border: Border.all(color: Colors.grey),
                    borderRadius: BorderRadius.circular(100),
                  ),
                  child: const Center(
                    child: Text(`your text`
                      "Login",
                      style: TextStyle(
                        color: Colors.white,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                ),
              ),
            ),
            const SizedBox(
              height: 100,
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                const Text("Do you have new Id?",
                    style: TextStyle(
                      fontSize: 14,
                      //fontWeight: FontWeight.wSymbol(figma.mixed),
                    )),
                GestureDetector(
                  onTap: () {
                    Navigator.pushNamed(context, '/register');
                  },
                  child: Text("Registration",
                      style: TextStyle(
                        color: Color(DefineColor.loginBtnColor),
                        fontSize: 14,
                        decoration: TextDecoration.underline,
                        decorationColor: Color(DefineColor.loginBtnColor),
                      )),
                ),
              ],
            )
         ],
      ));
  }
}`

I really don't know what the problem is. Please help me..


Solution

  • Seems like you are using Provider wrong. The reason you get null is MapProvider is not the same instance in LoginPage and HomePage.

    Instead of instantiate MapProvider in LoginPage, you should provide it up the widget tree, on node which are ancestor of both LoginPage and HomePage.

    e.g. Above App:

    void main() {
      runApp(
        ChangeNotifierProvider(
          create: (context) => MapProvider(),
          child: const MyApp(),
        ),
      );
    }
    

    Then you can access it in LoginPage like:

    Provider.of<MapProvider>(context, listen: false).locateMe();