티스토리 뷰

flutter

flutter thread 분석

길 킴 2024. 6. 5. 14:33
728x90

 

예시 코드 

시나리오: 아래의 4개 버튼 클릭 시, progress bar 보여주고 2초후에 text 변경과 함께 progress bar 가 사라진다. 

child: Column(
  crossAxisAlignment: CrossAxisAlignment.center,
  children: [
    Builder(builder: (_) {
      if (loadedData == null) {
        return const SizedBox();
      }
      if (loadedData!.isEmpty) {
        return const CircularProgressIndicator();
      }
      return Text(loadedData!);
    }),
    const SizedBox(
      height: 10,
    ),
    ElevatedButton(onPressed: onTapMethodCall, child: const Text('Call Method')),
    const SizedBox(
      height: 10,
    ),
    ElevatedButton(
        onPressed: onTapMethodCallWithFutureDelay, child: const Text('Call Method With Future Delay')),
    const SizedBox(
      height: 10,
    ),
    ElevatedButton(onPressed: onTapMethodCallWIthIsolate, child: const Text('Call Method With Isolate')),
    const SizedBox(
      height: 10,
    ),
    ElevatedButton(onPressed: onTapCancelIsolate, child: const Text('Cancel Method')),
  ],
)

 

아래 버튼 종류

1) Call Method : 

Future<void> onTapMethodCall() async {
  setState(() {
    loadedData = '';
  });
  sleep(const Duration(milliseconds: 2000));
  setState(() {
    loadedData = 'just sleep over';
  });
}


2) Call Method With Future Delay : 

Future<void> onTapMethodCallWithFutureDelay() async {
  setState(() {
    loadedData = '';
  });
  await Future.delayed(const Duration(milliseconds: 2000));
  setState(() {
    loadedData = 'just sleep over';
  });
}


3) Call Method With Isolate : 

Future<void> onTapMethodCallWIthIsolate() async {
  setState(() {
    loadedData = '';
  });

  _isolate = await Isolate.spawn<SendPort>(sleepApp, _receivePort.sendPort);
}

4) Cancel Method :

void onTapCancelIsolate() {
  _isolate.kill(priority: Isolate.immediate);

  setState(() {
    loadedData = 'Task canceled';
  });
}

 

과연 결과는?  

1) Call Method : 2초동안 UI block 되고, 2초후에 text 변경 성공 

2) Call Method With Future Delay : UI block 없이 text 변경 성공 

3) Call Method With Isolate : UI block 없이 text 변경 성공 

4) Cancel Method : 3번 실행도중 호출 시, 3번 작업 cancel 성공 

 

⚠️ 주의사항

Isolate 함수 에러가 발생할 수 있다. 
Isolate 함수 안에 사용되는 첫번째 인자는 별도의 메모리 공간에서 실행된다는 것을 명심해야 한다. 
즉, 메모리가 공유되지 않기 때문에 최상위 함수거나 static 함수로 독립적으로 존재해야 한다. 

Isolate.spawn<SendPort>(sleepApp, _receivePort.sendPort);

에러가 났을 때, Chat GPT 답변 => 

Dart에서 Isolate를 사용할 때, Isolate로 전달되는 함수는 정적(static) 함수이거나 최상위 함수여야 합니다. 이 규칙을 지키지 않으면 오류가 발생합니다. 그 이유는 다음과 같습니다:

1. Isolate의 독립성: Isolate는 별도의 메모리 공간에서 실행됩니다. 따라서, Isolate로 전달되는 함수는 클래스의 인스턴스 상태나 컨텍스트에 의존할 수 없습니다. 이는 Isolate가 다른 Isolate 또는 메인 프로그램의 상태를 직접 접근할 수 없도록 보장하기 위함입니다.

2. 함수 시리얼라이제이션: Isolate는 함수 및 데이터를 시리얼라이즈하여 전달합니다. 클래스의 인스턴스 메서드는 인스턴스와 연결된 상태를 포함하고 있어서 시리얼라이즈하기 어렵습니다. 반면, 정적 함수나 최상위 함수는 이런 상태가 없기 때문에 쉽게 시리얼라이즈할 수 있습니다.

3. 성능 및 안정성: 독립된 메모리 공간에서 실행되는 Isolate는 상태 공유로 인한 부작용을 방지하여 성능과 안정성을 향상시킵니다.

따라서, sleepApp 함수를 static으로 정의하면 Isolate가 이를 독립적으로 실행할 수 있기 때문에 오류가 발생하지 않습니다.

 

전체코드 참고 

class _MyHomePageState extends State<MyHomePage> {
  String? loadedData;
  late Isolate _isolate;
  final _receivePort = ReceivePort();

  @override
  void initState() {
    super.initState();
    _receivePort.listen((message) {
      setState(() {
        loadedData = message.toString();
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          title: Text(widget.title),
        ),
        body: Center(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Builder(builder: (_) {
                if (loadedData == null) {
                  return const SizedBox();
                }
                if (loadedData!.isEmpty) {
                  return const CircularProgressIndicator();
                }
                return Text(loadedData!);
              }),
              const SizedBox(
                height: 10,
              ),
              ElevatedButton(onPressed: onTapMethodCall, child: const Text('Call Method')),
              const SizedBox(
                height: 10,
              ),
              ElevatedButton(
                  onPressed: onTapMethodCallWithFutureDelay, child: const Text('Call Method With Future Delay')),
              const SizedBox(
                height: 10,
              ),
              ElevatedButton(onPressed: onTapMethodCallWIthIsolate, child: const Text('Call Method With Isolate')),
              const SizedBox(
                height: 10,
              ),
              ElevatedButton(onPressed: onTapCancelIsolate, child: const Text('Cancel Method')),
            ],
          ),
        ));
  }

  Future<void> onTapMethodCall() async {
    setState(() {
      loadedData = '';
    });
    sleep(const Duration(milliseconds: 2000));
    setState(() {
      loadedData = 'just sleep over';
    });
  }

  Future<void> onTapMethodCallWithFutureDelay() async {
    setState(() {
      loadedData = '';
    });
    await Future.delayed(const Duration(milliseconds: 2000));
    setState(() {
      loadedData = 'just sleep over';
    });
  }

  Future<void> onTapMethodCallWIthIsolate() async {
    setState(() {
      loadedData = '';
    });

    _isolate = await Isolate.spawn<SendPort>(sleepApp, _receivePort.sendPort);
  }

  void onTapCancelIsolate() {
    _isolate.kill(priority: Isolate.immediate);

    setState(() {
      loadedData = 'Task canceled';
    });
  }

  static void sleepApp(SendPort sendPort) {
    sleep(const Duration(milliseconds: 2000));
    sendPort.send("Completion");
  }
}

 

 


참고자료 
- https://rlg1133.tistory.com/143

'flutter' 카테고리의 다른 글

Provider 라이브러리 사용  (0) 2020.02.23
How Flutter renders Widget  (0) 2019.11.23
Mac에 Fultter로 Android 개발하기 - 2  (0) 2019.10.18
Mac에 Fultter로 Android 개발하기 - 1  (0) 2019.10.18
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/06   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
글 보관함