최근 매우 재미있게 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가 불러지는 것이였다.
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해주면 된다!!