3 posts

·Tech·Flutter

Deepening Flutter asynchronous tasks

Full page →
Flutter

Entering

Synchronous means that all tasks are processed sequentially, while asynchronous means that tasks are processed in parallel. That is, it starts the next task without waiting for the completion of the previously started task.

Comparing synchronous and asynchronous in code

Synchronous code

After all tasks 1 are completed, task 2 will start and the message ‘All tasks completed’ will be displayed.

void main() {
print('작업 1 시작');
task1();
print('작업 2 시작');
task2();
print('모든 작업 완료');
}
void task1() {
for (int i = 0; i < 1000000000; i++) {}
print('작업 1 완료');
}
void task2() {
print('작업 2 완료');
}

// result

작업 1 시작
작업 1 완료
작업 2 시작
작업 2 완료
모든 작업 완료

Asynchronous code

The following code is based on an asynchronous method, and as a result, you can see that the task is processed according to duration. This means that there is a mismatch in the order of code operations within wait.

void main() async {
print('작업 시작');
await Future.wait([
task1(),
task2(),
task3()
]);
print('모든 작업 완료');
}
Future<void> task1() async {
await Future.delayed(Duration(seconds: 2));
print('작업 1 완료');
}
Future<void> task2() async {
await Future.delayed(Duration(seconds: 1));
print('작업 2 완료');
}
Future<void> task3() async {
await Future.delayed(Duration(seconds: 3));
print('작업 3 완료');
}

// result

작업 시작
작업 2 완료
작업 1 완료
작업 3 완료
모든 작업 완료

Deepening Flutter asynchronous tasks

State management and asynchrony

As in the code presented above, an example is to delay until the result of an asynchronous operation is obtained and then reflect it in the setState state. This applies even if the operation starts asynchronously, but the resulting processing must appear synchronous to the user.

  • You can see asynchronous processing using async and await. Add async to create an asynchronous function, and await waits for Future to complete and returns the result when complete.
  • Future is an object that represents the result of an asynchronous operation and provides results or errors after the operation is completed.
  • You can prevent duplicate requests by processing whether the button is activated or not (setState) before and after returning Future.
Future<void> resetGameTiles(int tile1, int tile2) async {
await Future.delayed(Duration(milliseconds: 1500));
setState(() {
tileStates[tile1] = false;
tileStates[tile2] = false;
});
selectedTile = -1;
}

Future chaining method

In addition to the above methods, Future provides a Future chaining method for asynchronous operations.

  • Future.then(), Future.catchError(), Future.whenComplete()
  • task1().then((value) => task2()).catchError((e) => print(e));
  • You can execute task2 according to the value of task1, and in the process, you can simply express tasks such as catching errors and outputting logs.

Difference between Future and Stream

Future returns data only once, and Stream is used for continuous stream processing, that is, returning multiple data asynchronously, like other languages. You can consider asynchronous state management using the StreamBuilder widget for real-time data processing.

Completer class

There is a way to complete a Future externally using Completer. An object that can control asynchronous operations and returns a Future object with completer.complete.

Future<String> fetchData() {
Completer<String> completer = Completer<String>();
Future.delayed(Duration(seconds: 2), () {
completer.complete('데이터 로드 완료');
});
return completer.future;
}

Why use Completer? Advanced control for asynchronous operations is available right away. This is because you can manually control the return completion point of Future, which is automatically completed as shown in the code.

  • Because it contains a Future object inside Completer

UI and FutureBuilder

FutureBuilder tracks the state through snapshots until Future completes. You can control completion and error states depending on the snapshot.connectionState state. During loading, CircularProgressIndicator is displayed and the result is returned after loading.

  • You can provide a message for error handling with snapshot.hasError.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('비동기 작업 예시')),
body: Center(
child: FutureBuilder<String>(
future: fetchData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();  // 로딩 중일 때 인디케이터
} else if (snapshot.hasError) {
return Text('에러 발생: ${snapshot.error}');
} else if (snapshot.hasData) {
return Text('결과: ${snapshot.data}');
} else {
return Text('데이터 없음');
}
},
),
),
);
}

Comments

No comments yet. Be the first!