[Flutter] riverpod provider dispose 문제

bluejoy·2022년 9월 19일
0

Flutter

목록 보기
7/15

발단

최근 매우 재미있게 riverpod 라이브러리를 사용해 상태 관리를 진행 중이였다.

riverpod에는 autoDispose라는 수식어?가 존재해 더이상 참조되지 않는 프로바이더를 dispose 해줄 수 있다.

그러나 자꾸 이상한 곳에서 dispose가 되는 버그가 발생했다.

문제의 코드

void pickVideo(
      {required bool isFromCam, required BuildContext context}) async {
    final ImagePicker picker = ImagePicker();
    _init();
    picker
        .pickVideo(source: isFromCam ? ImageSource.camera : ImageSource.gallery)
        .then((image) async {
      if (image == null) {
        return;
      }
      state = state.copyWith(videoPath: image.path);
      Future.microtask(
        () {
          // TODO check
          context.pushNamed(storyUploadRouteName);
        },
      );
    });

위 코드에서 ImagePicker를 이용해 앱 외부(갤러리 등)에서 사진을 고르게 되는데 이 외부로 간다는 것 자체가 문제였다.

provider를 참조하는 화면이 없어서 dispose가 불러지는 것이였다.

시도. autoDispose 제거

autoDipose를 제거하고 명시적으로 dispose를 불러주려고 했다.

void upload(BuildContext context) async {
    final Result<void> result =
        await repository.createStory(storyUpload: state);
    result.when(
      success: (value) {
        context.pop();
        customShowDialog(
            context: context, title: '업로드 성공', content: '스토리 업로드 완료');
        dispose(); // dispose 호출
      },
      error: (message) {
        customShowDialog(context: context, title: '에러', content: message);
      },
    );
  }

그러나 이러니 다시 필요한 곳에서 provider를 참조했을 때 재생성이 되지 않는 버그가 발생했다.
https://github.com/rrousselGit/riverpod/issues/662 를 보아하니 dispose를 명시적으로 호출하는 것은 정답이 아니였다.

정답

void pickVideo(
      {required bool isFromCam, required BuildContext context}) async {
    final ImagePicker picker = ImagePicker();
    _init();
    KeepAliveLink link = ref.keepAlive();
    picker
        .pickVideo(source: isFromCam ? ImageSource.camera : ImageSource.gallery)
        .then((image) async {
      link.close();
      if (image == null) {
        return;
      }
      state = state.copyWith(videoPath: image.path);
      Future.microtask(
        () {
          // TODO check
          context.pushNamed(storyUploadRouteName);
        },
      );
    });
  }

https://github.com/rrousselGit/riverpod/issues/1337
여기서 힌트를 얻었다.
keepAlive를 이용해 provider가 살아있도록 해준 후 화면 밖 작업이 완료된다면 close해주면 된다!!

profile
개발자 지망생입니다.

0개의 댓글