목표

10초마다 위치 정보를 받아오는 provider를 만들고, 위치 정보가 바뀌면 특정 화면 UI에 경도와 위도 값을 표시해주고 싶음

Riverpod

Flutter/Dart를 위한 반응형 캐싱 프레임워크(Reactive caching framework)로 getX, provider 등과 같은 플러터의 상태 관리 패키지 중 하나

프로젝트 세팅

라이브러리 세팅 pubspec.yaml

1
2
3
dependencies:
  flutter_riverpod: ^2.5.1
  geolocator: ^12.0.0

riverpod 세팅

  • riverpod provider을 사용하기 위해서는 앱의 루트를 ProviderScope로 감싸주어야 함
1
2
3
4
void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const ProviderScope(child: MyApp()));
}
  • 화면을 ConsumerStatefulWidget으로 감싸면 provider를 참조할 수 있도록 하는 ref 객체를 사용할 수 있게 됨
1
2
3
4
5
6
7
8
9
10
11
12
13
class LocationInfoPage extends ConsumerStatefulWidget {
  const LocationInfoPage({super.key});

  @override
  ConsumerState<ConsumerStatefulWidget> createState() => LocationInfoState();
}

class LocationInfoState extends ConsumerState<LocationInfoPage> {
  @override
  Widget build(BuildContext context) {
    // 코드 작성...
  }
}

provider 생성 location_provider.dart

  • locationProvider를 전역으로 생성해 어디서든지 해당 provider를 참조할 수 있도록 함
1
2
3
final locationProvider = ChangeNotifierProvider<LocationProvider>((ref) {
  return LocationProvider();
});

전체 코드

main.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const ProviderScope(child: MyApp()));
}

class MyApp extends ConsumerStatefulWidget {
  const MyApp({super.key});

  @override
  ConsumerState<MyApp> createState() => _MyAppState();
}

class _MyAppState extends ConsumerState<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Location updated?',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const LocationInfoPage(),
    );
  }
}

location_provider.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class LocationData {
  final double latitude;
  final double longitude;

  LocationData({required this.latitude, required this.longitude});
}

final locationProvider = ChangeNotifierProvider<LocationProvider>((ref) {
  return LocationProvider();
});

class LocationProvider extends ChangeNotifier {
  LocationData? _currentLocation;

  LocationData? get currentLocation => _currentLocation;

  late Timer locationTimer;

  // 위치 업데이트 메서드
  Future<void> updateLocation() async {
    try {
      // 10초마다 위치 업데이트
      locationTimer =
          Timer.periodic(const Duration(seconds: 10), (timer) async {
        debugPrint("==== locationProvider... updateLocation ====");

        Position position = await Geolocator.getCurrentPosition();
        _currentLocation = LocationData(
            latitude: position.latitude, longitude: position.longitude);

        notifyListeners(); // Provider에게 상태 변경을 알림
      });
    } catch (e) {
      debugPrint('Error updating location: $e');
    }
  }

  @override
  void dispose() {
    super.dispose();
    locationTimer.cancel();
  }
}

location_info.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class LocationInfoPage extends ConsumerStatefulWidget {
  const LocationInfoPage({super.key});

  @override
  ConsumerState<ConsumerStatefulWidget> createState() => LocationInfoState();
}

class LocationInfoState extends ConsumerState<LocationInfoPage> {
  @override
  void initState() {
    super.initState();
    requestLocationPermission();
  }

  // 위치 권한 받아오기
  Future<void> requestLocationPermission() async {
    LocationPermission permission;

    permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) {
        debugPrint("location permission is denied.");
        return;
      } else {
        ref.read(locationProvider).updateLocation();
      }
    } else {
      ref.read(locationProvider).updateLocation();
    }
  }

  @override
  Widget build(BuildContext context) {
    final locationData = ref.watch(locationProvider); // provider의 값을 얻어 변화를 모니터링

    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
                "🏃‍♀️ latitude: ${locationData.currentLocation?.latitude ?? ''}"),
            Text(
                "🏃‍♀️ longitude: ${locationData.currentLocation?.longitude ?? ''}"),
          ],
        ),
      ),
    );
  }
}

결과물

Leave a comment