Flutter에서 대화 상자를 열 때 비동기 처리

9832 단어 DartFlutter
이 기사는 CBcloud Advent Calendar 2020의 20 일째 기사입니다.

저는 CBcloud에 toC 서비스인 PickGo 쇼핑의 앱을 주로 담당하는 모바일 앱 엔지니어로 참여하고 있습니다.
PickGo 쇼핑은 전문 드라이버에게 쇼핑을 대행해 주시고, 원하는 것이 당일 바로 도착하는 앱입니다.
현재 무료 배송 캠페인을하고 있기 때문에 좋으면이 기회에 꼭 시험해보십시오!

이 기사에서는 자신이 업무 중에 짜낸 기술 중 하나를 소개합니다.

대화 상자를 낼 때 비동기 처리를 원합니다.



사용자의 조작으로부터 다이얼로그를 낼 때, 그 내용을 API로부터 취득하고 싶은 상황을 생각합니다.

↓이


뭔가 비동기식으로 통신하고 있다면, 로드 중임을 이런 식으로 인디케이터를 내는 것으로 친절하게됩니다. 이것은 별로 원래의 페이지에서 해도 좋지만, 어차피 다이얼로그를 내면 대화상자에서 하는 편이 뭔가 외형도 좋은 생각이 듭니다.

이것을 실현하기 위해서, 우선 다이얼로그의 Widget상에서 보통의 페이지용 Widget과 같이 StatefulWidget 로 말하는 initState
…그러나 그냥 하는 것만으로는 잘 가지 않고. 조금 전의 이야기이므로 기억이 모호합니다만, 확실히 Provider로 잘 ChangeNotifier 를 호출할 수 없었던 것이 원인이었다고 생각합니다. 친절하게 ChangeNotifier 를 사용하면 되었을지도 모르지만, StatefukWidget

구현 방법



여러가지 생각했는데, 이하의 방법으로 침착했습니다.
  • StatefulWidget 래퍼 함수 준비
  • 내부에서 showDialog를 사용하여 ViewModel 역할을하는 Controller를 이용한다.
  • 래퍼의 인수에 실제로 실시하는 비동기 처리의 내용과 그 결과를 포함한 Provider.value 적인 것을 정의해 둔다

  • 구현은 다음과 같습니다.
    
    typedef ResultBuilder<R> = Widget Function(BuildContext, R);
    typedef PreProcess<R> = Future<R> Function();
    
    Future<T> showAsyncDialog<T, R>({
      BuildContext context,
      ResultBuilder<R> resultDialogBuilder,
      PreProcess<R> process,
    }) async {
      final controller = _AsyncDialogController(process: process);
    
      final dialogResult = await showDialog(
          context: context,
          builder: (context) {
            final dialog = Builder(
              builder: (context) {
                final isLoading = context.select(
                    (_AsyncDialogController<R> controller) => controller.isLoading);
                final result = context.select(
                    (_AsyncDialogController<R> controller) => controller.result);
                return isLoading
                    ? const PlaceholderDialog()
                    : resultDialogBuilder(context, result);
              },
            );
    
            return ChangeNotifierProvider.value(
              value: controller,
              child: dialog,
            );
          });
    
      return dialogResult;
    }
    
    class _AsyncDialogController<T> extends ChangeNotifier {
      _AsyncDialogController({this.process}) {
        Future(() async {
          result = await process();
          isLoading = false;
          notifyListeners();
        });
      }
    
      bool isLoading = true;
      final Future<T> Function() process;
      T result;
    }
    

    대화 상자에서 Provider 액세스는 h tps : // s t c ゔ ぇ rf ぉ w. 코 m / 쿠에 s 치온 s / 57968453 / 호 w와 어서 s pp ゔ ぃ에서 rp ゔ ぃ에서 rs을 참조했습니다.
    WidgetBuilder 는 로드중에 발행하는 다이얼로그로, 결과의 다이얼로그와는 별개로 하고 있습니다.
    여기의 실장을 궁리하면 처리 완료했을 때에 애니메이션 첨부로 결과의 다이얼로그가 원활하게 낼 수 있을 것 같은 생각이 듭니다.

    이용측은 이런 느낌입니다.
    TextButton(
      onPressed: () => showAsyncDialog<void, String>(
        context: context,
        resultDialogBuilder: (context, result) => AlertDialog(
          content: Text(result),
        ),
        process: () async {
          await Future.delayed(const Duration(seconds: 2));
          return 'hoge';
        },
      ),
      child: Text('Tap me'),
    ),
    

    실장해 보면 뭐라고 없는 것이었습니다만, 개인적으로 만들어 두면 상당히 편리하다고 생각했습니다.

    좋은 웹페이지 즐겨찾기