ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Flutter] Flutter Hook에서 WebView가 포함된 비동기 함수를 useEffect에서 선언했을 때 나오는 Zone mismatch 에러에 대해서...
    Flutter 2024. 9. 3. 18:21

    요즘 기존의 Stateful, Stateless, Consumer Widget... 등등을 HookWidget, HookConsumerWidget으로 수정하는 작업을 하고 있는데, 이때 발생한 Zone mismatch 에러에 대해서 정리해보려고 한다.

     

     

    기존 코드

    import 'package:project_name/common/const/color.dart';
    import 'package:desktop_webview_window/desktop_webview_window.dart';
    import 'package:flutter/material.dart';
    
    class WebviewScreen extends StatefulWidget {
      const WebviewdScreen({super.key});
    
      @override
      State<WebviewScreen> createState() => _WebviewScreenState();
    }
    
    class _WebviewScreenState extends State<WebviewScreen> {
    
      @override
      void initState() {
        super.initState();
        _openWebview(); // 요 부분
      }
    
      @override
      Widget build(BuildContext context) {
        return Center(
          child: Container(
            decoration: BoxDecoration(
              color: BUTTON_PRESS_COLOR,
              borderRadius: BorderRadius.circular(100),
            ),
            height: 200,
            width: 200,
            child: IconButton(
              onPressed: () {
                _openWebview();
              },
              icon: Image.asset(
                'asset/image/webview_icon.png',
                color: Colors.white,
                height: 130,
              ),
            ),
          ),
        );
      }
    
      void _openWebview() async {
        const url = "https://google.co.kr";
    
        final webview = await WebviewWindow.create();
        webview.launch(url);
      }
    }

     

    HookWidget 으로 바꾼 코드

    import 'package:project_name/common/const/color.dart';
    import 'package:desktop_webview_window/desktop_webview_window.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_hooks/flutter_hooks.dart';
    
    class WebviewScreen extends HookWidget {
      const WebviewScreen({super.key});
    
      @override
      Widget build(BuildContext context) {
    
        useEffect((){
          _openWebview();
          return;
        },[]);
    
        return Center(
          child: Container(
            decoration: BoxDecoration(
              color: BUTTON_PRESS_COLOR,
              borderRadius: BorderRadius.circular(100),
            ),
            height: 200,
            width: 200,
            child: IconButton(
              onPressed: () {
                _openWebview();
              },
              icon: Image.asset(
                'asset/image/webview_icon.png',
                color: Colors.white,
                height: 130,
              ),
            ),
          ),
        );
      }
    
      void _openWebview() async {
        const url = "https://google.co.kr";
    
        final webview = await WebviewWindow.create();
        webview.launch(url);
      }
    }

     

    이렇게 수정했는데 onPressed를 눌러 버튼을 동작할 때 마다, 

    이런 에러가 발생했다.

     

    찾아보니  Flutter는 이벤트 루프와 같은 실행 컨텍스트를 관리하기 위해 Zone을 사용하는데, desktop_webview_window 라이브러리에서 사용되는 WebView가 Flutter가 처음 실행된 Zone과 다른 Zone에서 호출되면서 이러한 문제가 발생한다고 한다.

     

    이를 내 코드에 대입해 보면 비동기 함수(Webview)를 StatefulWidget의 initState에서 실행시켰을 때는 Zone mismatch 에러가 안나지만 HookWidget의 ueseEffect 안에서 실행시켰을 때는 나는 이유는

    • StatefulWidget의 initState는 Flutter의 기본 Zone에서 실행되기 때문에 WebView를 초기화하는 코드가 메인 UI Zone에서 실행되지만
    • HookWidget의 useEffect는 Hooks 라이브러리에서 제공하는 훅으로 Flutter 위젯의 생명주기와 연결되어 실행된다. 때문에 비동기 코드가 실행될 때 다른 Zone에서 실행될 수 있다.

     

    해결방법

    Flutter Hook의 useEffect에서 비동기 함수 같은 함수들을 사용할 때에는

    WidgetsBinding.instance.addPostFrameCallback 안에 원하는 함수를 넣어 다음과 같이 사용하면 된다.

    useEffect(() {
         WidgetsBinding.instance.addPostFrameCallback((_) {
            _openWebview();
          });
          return;
        }, []);

     

Designed by Tistory.