DevBoi

[Flutter] Riverpod 적용기 (기본) 본문

[Mobile]/[Flutter]

[Flutter] Riverpod 적용기 (기본)

HiSmith 2025. 2. 4. 00:19
반응형

Flutter로 Riverpod를 적용하여 개발을 진행해보자

Riverpod는 누구나 알다싶이, 상태 관리에 대한 기술이다.

 

상태관리란, 데이터가 변경될때, 메모리관리 또는 UI 컴포넌트 영향등을 관리해주는 기술이라고 이해하면 편하다.

야생의 개발자의 경우에는 그냥 일단 개발을 따라 해보고 천천히 이해하는데

나도 약간 이런걸 좋아하는것같다?

 

일단 적용해보자

 

1. Riverpod 플러그인 추가

flutter_riverpod: ^2.6.1

 

2. Riverpod 요소 State

State는 상태관리의 대상이 되는 Entity라고 이해하면 편하다.

class SensorState {
  final double accX, accY, accZ;
  final double gyroX, gyroY, gyroZ;

  SensorState({
    this.accX = 0.0,
    this.accY = 0.0,
    this.accZ = 0.0,
    this.gyroX = 0.0,
    this.gyroY = 0.0,
    this.gyroZ = 0.0,
  });
}

 

 

 

3. Riverpod 요소 Notifier

Notifier의 존재 이유는 이렇다.

상태관리에 대한 State의 값을 변경하거나, 필요한 동작들을 이 Notifier를 통해서 진행하게 된다.

class SensorNotifier extends StateNotifier<SensorState> {
  SensorNotifier() : super(SensorState());

  StreamSubscription<AccelerometerEvent>? _accelerometerSubscription;
  StreamSubscription<GyroscopeEvent>? _gyroscopeSubscription;

  bool isListening = false;

  void startListening() {
    if (isListening) return;
    isListening = true;

    _accelerometerSubscription = accelerometerEventStream().listen((event) {
      state = SensorState(
        accX: event.x,
        accY: event.y,
        accZ: event.z,
        gyroX: state.gyroX,
        gyroY: state.gyroY,
        gyroZ: state.gyroZ,
      );
    });

    _gyroscopeSubscription = gyroscopeEventStream().listen((event) {
      state = SensorState(
        accX: state.accX,
        accY: state.accY,
        accZ: state.accZ,
        gyroX: event.x,
        gyroY: event.y,
        gyroZ: event.z,
      );
    });
  }

  void stopListening() {
    if (!isListening) return;
    isListening = false;

    _accelerometerSubscription?.cancel();
    _gyroscopeSubscription?.cancel();
  }

  @override
  void dispose() {
    _accelerometerSubscription?.cancel();
    _gyroscopeSubscription?.cancel();
    super.dispose();
  }
}

 

 

4. Riverpod 요소 provider 선언

이제 ui에서 호출해서 꺼내쓸수있도록, 선언을 해준다.

개발자의 기호에 따라서 특정 파일에 모아 놓는 경우도있다

final sensorProvider = StateNotifierProvider<SensorNotifier, SensorState>((ref) {
  return SensorNotifier();
});

 

 

5. Riverpod ui에 매핑

 

이런식으로 하면, 홈에서 해당 프로바이더를 호출하고, 해당 프로바이드의 notifier를 통해 state를 상태관리할 수있게 된다.

class HomeView extends ConsumerWidget {

  StreamSubscription<AccelerometerEvent>? _accelerometerSubscription;
  StreamSubscription<GyroscopeEvent>? _gyroscopeSubscription;
  bool isRecording = false;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final sensorState = ref.watch(sensorProvider);
    final sensorNotifier = ref.read(sensorProvider.notifier);
  return  GestureDetector(
          onTap: () {
        FocusScope.of(context).unfocus();
        },
      child: Scaffold(
        body: SingleChildScrollView(
          child: Container(
            width: mediaQueryData.size.width,
            height: mediaQueryData.size.height * 0.8,
            color: Color(0xFFD6DBED),
            child: Padding(
              padding: EdgeInsets.only(top: 30.v,left: 40.h),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    '항공기 상태',
                    style: TextStyle(
                      color: Color(0xFF233B6E),
                      fontSize: 13,
                      fontFamily: 'Pretendard',
                      fontWeight: FontWeight.w800,
                    ),
                  ),
                  SizedBox(height: 5.v),
                  AirplaneStatusWidget(),
                  SizedBox(height: 15.v,),
                  Text(
                    '통신 상태 (클라우드 서버)',
                    style: TextStyle(
                      color: Color(0xFF233B6E),
                      fontSize: 13,
                      fontFamily: 'Pretendard',
                      fontWeight: FontWeight.w800,
                    ),
                  ),
                  SizedBox(height: 5.v),
                  NetworkStatusWidget(),
                  SizedBox(height: 10.v),
                  Text(
                    '저장 공간',
                    style: TextStyle(
                      color: Color(0xFF233B6E),
                      fontSize: 13,
                      fontFamily: 'Pretendard',
                      fontWeight: FontWeight.w800,
                    ),
                  ),
                  SizedBox(height: 5.v),
                  StorageStatusWidget(),
                  SizedBox(
                      width: mediaQueryData.size.width * 0.8,
                      child: NovaChartWidget()
                  )
                ],
              ),
            ),
            ),
        ),
        floatingActionButton: SpeedDial(
          activeBackgroundColor: Color(0xFF233B6E),
          buttonSize: Size(90, 90), // FAB 크기 키우기
          childrenButtonSize: Size(90, 90), // 펼쳐지는 버튼 크기 키우기
          spaceBetweenChildren: 10,
          backgroundColor: Color(0xFF233B6E),
          overlayColor: Colors.transparent,
          animatedIcon: AnimatedIcons.menu_close,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(7), // 네모난 모양을 위해 둥근 모서리 설정
          ),
          children: [
            SpeedDialChild(
              child: Icon(
                isRecording ? Icons.stop : Icons.play_arrow,
                color: Color(0xFF233B6E),
                size: 60,),
              label: isRecording ? "측정 중지" : "측정 시작",
              onTap: ((){
                  isRecording = !isRecording;
                  if(isRecording){
                    sensorNotifier.startListening();
                  }
                  else{
                    sensorNotifier.stopListening();
                  }
              }),
            ),
            SpeedDialChild(
              child: Icon(Icons.cloud_upload,color: Color(0xFF233B6E),size: 60,),
              label: "업로드",
              onTap: ((){

              }),
            ),
          ],
        ),
      )
  );
  }
}

 

 

일단 이런식으로 사용하면 된다.

 

나는 screen - view - widget - provider의 개념을 주로 쓴다.

스크린은 다양한 view를 가질수 있고, view는 다양한 widget을 사용할 수 있다.

공통 widget이 많은 경우, 패키지를 상단으로 빼기도한다.

 

그리고 이 view안에서 provider를 쓰게 된다.

 

아래는 패키지 구조이다. 기호나 용도에 따라서 바꾸면 된다

 

 

 

즐코하자

반응형