인프런 커뮤니티 질문&답변

정충효님의 프로필 이미지
정충효

작성한 질문수

플러터 StreamProvider 중지에 대해 질문있습니다.

해결된 질문

작성

·

295

0

버튼 클릭시 trackingOff()를 호출해서 중지시킬려고 해도 StreamProvider가 중지가 되지않아서 그러는데 StreamProvider는 중지 시킬 수 없나여?

class LocationUtil {
  late UserLocation userLocation;
  late Position _currentPosition;
  late LocationPermission checkPermission;
  StreamSubscription<Position>? positionStream;
  Geolocator geolocator = Geolocator();
  StreamController<UserLocation> _positionController =
      StreamController<UserLocation>();

  Stream<UserLocation> get locationStream => _positionController.stream;

  final LocationSettings locationSettings =
      LocationSettings(accuracy: LocationAccuracy.high);

  // 추적 버튼 클릭시에만 현재 위치 주기적으로 업데이트
  LocationUtil() {
    // 사용자의 현재 위치 계속 업데이트해주기
    positionStream =
        Geolocator.getPositionStream(locationSettings: locationSettings)
            .listen((location) {
      _positionController
          .add(UserLocation(location.latitude, location.longitude));
    });
  }

  Future<UserLocation> getCurrentLocation() async {
    try {
      final isLocationEnabled = await Geolocator.isLocationServiceEnabled();
      checkPermission = await Geolocator.checkPermission();
      log("${isLocationEnabled} isLocationEnabled 확인");
      // 권한이 없을때
      if (!isLocationEnabled) {
        log("${checkPermission} checkPermission 확인");
        // 권한 설정 확인
        if (checkPermission == LocationPermission.denied ||
            checkPermission == LocationPermission.deniedForever) {
          checkPermission = await Geolocator.requestPermission();
        }
        // 한번더 권한 취소햇으면
        if (checkPermission == LocationPermission.denied ||
            checkPermission == LocationPermission.deniedForever) {
          throw Exception("denied'");
        }
      } else if (isLocationEnabled &&
          (checkPermission == LocationPermission.always ||
              checkPermission == LocationPermission.whileInUse)) {
        _currentPosition = await Geolocator.getCurrentPosition(
            desiredAccuracy: LocationAccuracy.high);
        userLocation =
            UserLocation(_currentPosition.latitude, _currentPosition.longitude);
      }
    } catch (e) {
      log("${e} 경복궁 보여줍시다.");
      userLocation = UserLocation(37.579887, 126.976870);
    }
    log("${userLocation.latitude},${userLocation.longitude} 현재 위치 위도 경도");
    return userLocation;
  }

  void closePosition() {
    if (positionStream != null) {
      log("종료입니다");
      positionStream!.cancel();
      _positionController.close();
      positionStream = null;
    } else {}
  }

  void trackingOn(){
    positionStream!.resume();
    _positionController.onResume;


  }
  void trackingOff(){
    log("off입니다.");
     positionStream!.pause();
    _positionController.onPause;
    log("${positionStream!.isPaused}");
  }
}
 StreamProvider<UserLocation>(
          initialData: Provider.of<LocationNotifier>(context).userLocation,
          create: (context) => LocationUtil().locationStream,
          child: Consumer<LocationNotifier>(
              builder: (context, locationNotifier, _) {
            CameraPosition initialCameraPosition = CameraPosition(
                target: LatLng(Provider.of<UserLocation>(context).latitude,
                    Provider.of<UserLocation>(context).longitude),
                zoom: 18);
            log("반복하는지 테스트입니다!!!!");
            animatedViewofMap(
                lat: Provider.of<UserLocation>(context).latitude,
                lng: Provider.of<UserLocation>(context).longitude,
                zoom: null);
            return Stack(children: [
              GoogleMap(
                initialCameraPosition: initialCameraPosition,
                myLocationEnabled: true,
                mapToolbarEnabled: true,
                myLocationButtonEnabled: true,
                mapType: MapType.normal,
                onMapCreated: (GoogleMapController controller) {
                  _controller.complete(controller);
                },
                markers: markerList,
              ),
            ]);
          }),
        )

답변 1

0

안녕하세요 정충효 님, 인프런 AI 인턴이에요.

위에 작성해주신 코드를 보면 LocationUtil 클래스 안에 UserProfile이라는 데이터를 스트림으로 제공하는 StreamProvider가 포함되어 있습니다. StreamProvider를 중지시키려는 trackingOff() 메소드를 통해 스트림을 일시적으로 멈추고 싶으신 것으로 이해하겠습니다.

하지만 StreamProvider의 스트림을 직접 중지시키는 기능은 제공되지 않습니다. StreamProvider는 스트림을 생성하고 구독자들에게 해당 스트림을 제공하는 역할을 합니다. 스트림을 멈추거나 다시 시작하는 것은 StreamProvider가 아닌 스트림 자체를 제어해야 합니다.

따라서 trackingOff() 메소드에서 스트림을 일시적으로 중지시키려면 positionStream 변수에 대한 제어를 해주어야 합니다. 현재 positionStreamGeolocator.getPositionStream() 메소드로 생성된 스트림에 대한 구독(subscription)을 참조하고 있습니다.

trackingOff() 메소드 안에서 positionStream을 멈추기 위해 positionStream!.pause()를 호출하셨는데, 이 부분에서 오류가 발생할 수 있습니다. 스트림을 일시적으로 멈추는 게 아니라 positionStream 구독 참조자체를 제거하고 싶다면 positionStream!.cancel()을 호출해야 합니다.

따라서 trackingOff() 메소드를 다음과 같이 수정하시면 됩니다:

void trackingOff() {
  log("off입니다.");
  positionStream?.cancel();
  _positionController.onPause;
  log("${positionStream?.isPaused}");
}

위의 수정사항을 적용한 뒤 trackingOff() 메소드를 호출하면 positionStream의 구독이 취소되고 스트림이 중지됩니다.

그러나 유의할 점은 StreamProviderStream<UserLocation>을 제공하는 역할을 하므로, 스트림을 중지시키면 StreamProvider가 새로운 데이터를 제공하지 않게 됩니다. 따라서 스트림을 중지시킬 경우, StreamProvider를 사용하는 구성요소에서 StreamBuilder 등으로 해당 스트림이 중지됨을 처리해주어야 합니다.

이점을 유의하시고 위의 수정사항을 참고하여 코드를 작성해보시기 바랍니다. 감사합니다!

정충효님의 프로필 이미지
정충효

작성한 질문수

질문하기