[Flutter/Riverpod] Background Position(Location) Stream /백그라운드 위치 Provider 구현하기

찌니·2023년 4월 17일
3

Flutter

목록 보기
10/13

이전에 했던 프로젝트를 provider에서 riverpod으로 리팩토링중이다.
다른 프로젝트들을 차차 하다보니 코드가 얼마나 구린지 알 수 있었다.. 전부 다 내 코드는 아니였지만 내 코드마저 매우 구린것을 알 수 있었음

이전에는 한 페이지에 한 프로바이더로 모든 값을 한 프로바이더에서 관리했는데 정말 말도 안되는 코드..ㅋ
한 프로바이더 안에서 주는 값이 10개가 넘었다.

대부분은 리팩토링하는 과정에서 어려움을 겪지 않았다. (사실 나 천재? 라고 생각했엇음) 하지만! 지금 하고있는 라이딩과 네비게이션 부분은 값이 너~무 많아서 관리하기가 너무 어렵다.
정말 프로바이더가 몇개가 생기는지 모르겠다. 심지어 연결된 부분도 많아 프로바이더 결합도 굉장히 많음.

현재는 사용자 라이딩 트래킹을 위한 위치 스트림을 만들어야하는데 정말 애먹는 중이다. 이 위치로 처리하는게 정말 많아서 연결짓는 데에도 애먹는즁,,

먼저 위치 스트림을 제공해주는 LocationService. locationSetting도 이 서비스에서 한다.

PositionService

class PositionService {
  static final PositionService _instance =
      PositionService._internal();

  late LocationSettings _locationSettings;

  static const int DISTANCE = 30;
  static const int DURATION_SECNOD = 2;

  factory PositionService() {
    return _instance;
  }

  PositionService._internal() {
    if (defaultTargetPlatform == TargetPlatform.android) {
      _locationSettings = AndroidSettings(
          accuracy: LocationAccuracy.high,
          distanceFilter: DISTANCE,
          forceLocationManager: true,
          intervalDuration: const Duration(seconds: DURATION_SECNOD),
          //(Optional) Set foreground notification config to keep the app alive
          //when going to the background
          foregroundNotificationConfig: const ForegroundNotificationConfig(
            notificationText: "백그라운드에서 사용자의 위치를 수집중입니다.",
            notificationTitle: "Riding-partner Running in Background",
            enableWakeLock: true,
          ));
    } else if (defaultTargetPlatform == TargetPlatform.iOS) {
      _locationSettings = AppleSettings(
        accuracy: LocationAccuracy.high,
        activityType: ActivityType.fitness,
        distanceFilter: DISTANCE,
        pauseLocationUpdatesAutomatically: true,
        // Only set to true if our app will be started up in the background.
        showBackgroundLocationIndicator: false,
      );
    } else {
      _locationSettings = const LocationSettings(
        accuracy: LocationAccuracy.high,
        distanceFilter: DISTANCE,
      );
    }
  }

  Stream<Position> position() {
    return Geolocator.getPositionStream();
  }
}

맨 아랫줄 보면 position 스트림을 제공한다

그리고 그 스트림을 받아 position 값을 제공하는 PositionProvider

PositionProvider

class PositionProvider extends StateNotifier<Position?> {
  PositionProvider() : super(null);

  
  set state(Position? value) {
    // TODO: implement state
    super.state = value;
  }

  void getPosition() {
    BackgroundLocationService().position().listen((event) {
      state = event;
    });
  }
}

스트림에서 값을 받아 position 값을 제공해주고 있다

참고로 사용해주는 곳을 보면 나는 position값과 다른 state값을 받아 사용자가 이동중에 서비스를 이용할때, polyline으로 지도에 라인을 그려주는 작업을 하는데, 그 라인은 LatLng 리스트로 이루어진다

// 위치 provider
final positionProvider = StateNotifierProvider<PositionProvider, Position?>(
    (ref) => PositionProvider());
    
//polyline provider    
final polylineCoordinatesProvider = StateProvider<List<LatLng>>((ref) => []);

// 주행 상태 provider
final ridingStateProvider = StateProvider((ref) => RidingState.before);

// polyline 생성 provider
final **provider = Provider((ref) {
  final state = ref.watch(ridingStateProvider);
  final position = ref.watch(positionProvider);
  if (state == RidingState.riding && position != null) {
    var polylist = ref.read(polylineCoordinatesProvider);
    polylist.add(LatLng(position.latitude, position.longitude));
    ref.read(polylineCoordinatesProvider.notifier).state = polylist;
  }
});

이것만 봐도.... 프로바이더가 4개가 생성된다 사실 실제 프로젝트에서는 position이 이 부분 말고도 많이 쓰이지만 polyline을 중심으로 보기만 해도 4개가 필요한 상황이다.
riverpod을 공부하다보면 riverpod 결합을 굉장히 많이 쓰게돼서 효율적으로 provider를 결합하고 관리하는 법에 대해 공부가 많이 필요한 것 같다.


굉장히 느리게 가고 화질도 안좋아서 구불구불 별로지만,,,, 이런 느낌이다
타이머를 걸어서 일정 시간에 한번만 값을 추가해 polyline을 그리면 더 깔끔한 라인이 나올듯 싶다 position이 변할때마다 하니 쉽지 않은듯 싶다

profile
찌니's develog

0개의 댓글