[비동기처리 심화]

1. 비동기 처리를 할 때는 Future를 사용 ( Future(함수) , Future.delayed(duration, 함수)

2. async키워드를 사용하면 await를 사용할 수 있고 Future가 완료 된 후 다음 코드가 실행되도록 한다. 즉, 비동기방식을 동기화로 처리가능

 

 

[ Future ]  - 선입선출(FIFO)구조의 이벤트 중 하나

1. 다트에 의해서 future 객체가 내부적인 배열에 등록

2. Future 관련해서 실행되어야 하는 코드들이 이벤트 큐에 등록

3. 불완전한 future 객체가 반환

4. Synchronous 방식으로 실행되어야 할 코드 먼저 실행

5. 최종적으로 실제적인 data값이 future 객체로 전달

void main(){
  print('Before the Future');
  Future((){
    print('Running the Future');
  }).then((_){
    print('Future is complete');
  });
  print('After the Future');
}

 

출력결과(Synchronous부분 실행 후 Future가 실행되고 그 이후 then부분 출력 됨 )

Before the Future
After the Future
Running the Future
Future is complete

 

* Async 키워드 *

1. Async 키워드를 사용하는 순간 메서드를 통해서 나오는 결과들은 모두 future

2. Await 키워드를 만날때까지 Synchronous 방식으로 코드 처리

3. Await 키워드를 만나면 future가 완료될 때까지 대기

4. future가 완료 되자마자 그 다음 코드들을 실행

5. Async는 메서드가 비동기방식임을 선언하는 것이고 Future는 하나의 객체로 만들어질 때는 미완성이나 미래의 어느 시점에 온전한 데이터가 되거나 문제가 발생시 에러를 반환하는 객체가 된다.

 

아래 예제는 Future객체를 사용해서 비동기적으로 프로그램을 작성했는데 제대로 된 출력이 되지 않음

String createOrderMessage() {
  var order = fetchUserOrder();
  return 'Your order is: $order';
}

Future<String> fetchUserOrder() =>
    // Imagine that this function is
// more complex and slow.
Future.delayed(
  const Duration(seconds: 2),
      () => 'Large Latte',
);

void main() {
  print('Fetching user order...');
  print(createOrderMessage());
}

 

async와 await를 사용해서 제대로 처리해보기

Future<String> createOrderMessage() async {
  var order = await fetchUserOrder();
  return 'Your order is: $order';
}

Future<String> fetchUserOrder() =>
    // Imagine that this function is
// more complex and slow.
Future.delayed(
  const Duration(seconds: 2),
      () => 'Large Latte',
);

Future<void> main() async {
  print('Fetching user order...');
  print(await createOrderMessage());
}

 

정리

1. 비동기 처리를 할 때는 Future를 사용

2. async키워드를 사용하면 await를 사용할 수 있고 Future가 완료 된 후 다음 코드가 실행되도록 한다. 즉, 비동기방식을 동기화로 처리가능

 

 

참고(자바스크립트의 비동기처리-거의 동일)

1.

https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%B2%98%EB%A6%AC-async-await

 

[JS] 📚 비동기처리 (async / await) 개념 & 문법 💯 정리

비동기 처리 방식 자바스크립트는 싱글 스레드 프로그래밍언어기 때문에 비동기처리가 필수적이다. 비동기 처리는 그 결과가 언제 반환될지 알수 없기 때문에 동기식으로 처리하는 기법들이

inpa.tistory.com

https://velog.io/@khy226/%EB%8F%99%EA%B8%B0-%EB%B9%84%EB%8F%99%EA%B8%B0%EB%9E%80-Promise-asyncawait-%EA%B0%9C%EB%85%90

 

동기, 비동기란? (+Promise, async/await 개념)

1. 동기 vs. 비동기 우선 차이점 부터 설명하자면, 동기는 '직렬적'으로 작동하는 방식이고 비동기는 '병렬적'으로 작동하는 방식이다. 즉, 비동기란 특정 코드가 끝날때 까지 코드의 실행을 멈추

velog.io

 

for, for in, foreach, while문

List<type>.generate

void basicLoop(){
  List<String> rainbow = ['1','2','3','4','5','6'];

  for(int i=0; i<rainbow.length; i++){
    print(rainbow[i]);
  }

  for(String x in rainbow){
    print(x);
  }

  rainbow.forEach((name){
    print(name);
  });
}

void main(){
  basicLoop();
  return;
}

 

[로또번호 생성기 ver_1]

아래 프로그램은 list자료형의 특성상 random으로 값을 생성할 때 중복된 값을 허용함

import 'dart:math';

List<int> lottoNmber(){
  var random = Random();
  List<int> lottoList = [];
  var num;

  for(int i=0; i<6; i++){
    num = random.nextInt(45) + 1;
    lottoList.add(num);
  }

  print('당첨번호');
  print(lottoList);

  return lottoList;
}

List<int> myNumber(){
  var random = Random();
  List<int> myList = [];
  var num;

  for(int i=0; i<6; i++){
    num = random.nextInt(45) + 1;
    myList.add(num);
  }

  print('내 추첨번호');
  print(myList);

  return myList;
}

void checkNumber(lottoList, myList){

  int match = 0;

  for(int lotto in lottoList){
    for(int myNum in myList){
      if(lotto == myNum){
        match++;
        print('당첨번호: $lotto');
      }
      //print("로또번호 = $lotto");
      //print("내 추첨번호 = $myNum");
    }
  }
  print("$match개의 당첨번호가 있습니다.");
}

void main(){
  List<int>lottoFinal = lottoNmber();
  List<int>myFinal = myNumber();

  checkNumber(lottoFinal, myFinal);

  return;
}

 

[로또번호 생성기 ver_2]

set을 사용해서 중복된 값 제외하기

import 'dart:math';

Set<int> lottoNmber(){
  final random = Random();
  final Set<int> lottoSet = {};

  while(lottoSet.length != 6){
    lottoSet.add(random.nextInt(45)+1);
  }
  print('당첨번호');
  print(lottoSet.toList());

  return lottoSet;
}

Set<int> myNumber(){
  final random = Random();
  final Set<int> mySet = {};

  while(mySet.length != 6){
    mySet.add(random.nextInt(45)+1);
  }

  print('내 추첨번호');
  print(mySet.toList());
  return mySet;
}

void checkNumber(lottoSet, mySet){

  int match = 0;

  for(int lotto in lottoSet){
    for(int myNum in mySet){
      if(lotto == myNum){
        match++;
        print('당첨번호: $lotto');
      }
      //print("로또번호 = $lotto");
      //print("내 추첨번호 = $myNum");
    }
  }
  print("$match개의 당첨번호가 있습니다.");
}

void main(){
  Set<int>lottoFinal = lottoNmber();
  Set<int>myFinal = myNumber();

  checkNumber(lottoFinal, myFinal);

  return;
}

 

리스트 제너레이터

List<int>.generate(45, (i) => i+1);

예시

void main(){
  var text = List<int>.generate(45, (i) => i+1);
  print(text);
}

 

 

dart언어 cascade notation

class Person{
  String? name;
  int? age;

  void set(int x){
    age = x;
  }

  void show(){
    print(name);
    print(age);
  }
}

void main(){
  Person p1 = Person();
  p1.set(30);
  p1.name = "Lee";
  p1.show();

  Person p2 = Person();
  p2..set(20)..name = "Kim"..show();

  Person p3 = Person();
  p3..set(40)
    ..name="Park"
    ..show();
}

 

cascade 표기법을 활용해서 랜덤한 lotto 숫자 6개 뽑아내기

void main(){
  var test = (List<int>.generate(45, (i) => i+1)..shuffle()).sublist(0,6);
  print(test);
}

 

다시 로또프로그램 만들기

 

 

shutdown -s -f -t 14000

shutdown -r -f -t 14000

shutdown -a

https://mozi.tistory.com/402

https://mockaroo.com/

 

Mockaroo - Random Data Generator and API Mocking Tool | JSON / CSV / SQL / Excel

Mock your back-end API and start coding your UI today. It's hard to put together a meaningful UI prototype without making real requests to an API. By making real requests, you'll uncover problems with application flow, timing, and API design early, improvi

mockaroo.com

 

 

 

Future 클래스는 비동기 작업을 할 때 사용

Future는 일정 소요시간 후에 실제 데이터나 에러를 반환

async클래스는 await 메서드를 가지고 잇으며, await메소드로 선언된 메소드는 응답이 처리될 때까지 대기하는 동기식으로 처리가 가능(데이터를 수신해서 다음 과정을 처리할 때 사용)

 

1.1 일반적인 동기적 상황(Sync)

import 'dart:io';

void main(){
  showData();
}

void showData(){
  startTask();
  acessData();
  fetchData();
}

void startTask(){
  String info1 = '요청수행 시작';
  print(info1);
}

void acessData(){
  Duration time = Duration(seconds: 3);
  sleep(time);
  String info2 = '데이터에 접속중';
  print(info2);
}

void fetchData(){
  String info3 = '잔액은 8,500원 입니다.';
  print(info3);
}

 

1.2 일반적인 비동기적상황(Async)

import 'dart:io';

void main(){
  showData();
}

void showData(){
  startTask();
  acessData();
  fetchData();
}

void startTask(){
  String info1 = '요청수행 시작';
  print(info1);
}

void acessData(){
  Duration time = Duration(seconds: 3);

  if(time.inSeconds>2){
    //sleep(time);
    Future.delayed(time, (){
      String info2 = "데이터 처리 완료";
      print(info2);
    });
  }else{
    String info2 = "데이터를 가져왔습니다.";
    print(info2);
  }
}

void fetchData(){
  String info3 = '잔액은 8,500원 입니다.';
  print(info3);
}

 

2.1 비동기처리로 인한 문제 발생

fetch함수가 acessData()함수의 리턴값이 필요한 상황

import 'dart:io';

void main(){
  showData();
}

void showData(){
  startTask();
  String account = acessData();
  fetchData(account);
}

void startTask(){
  String info1 = '요청수행 시작';
  print(info1);
}

String acessData(){
  String account="";

  Duration time = Duration(seconds: 3);

  if(time.inSeconds>2){
    //async로 처리되는 부분
    Future.delayed(time, (){
      account = "8,500만원";
      print(account);
    });
  }else{
    String info2 = "데이터를 가져왔습니다.";
    print(info2);
  }
  return account;
}

void fetchData(String account){
  String info3 = '잔액은 $account원 입니다.';
  print(info3);
}

 

2.2 문제 해결

 - 우선 acessData함수는 비동기 함수로 Future.delayed함수가 리턴이 된 후 나머지 문장이 실행된다.

 - Future.delayed함수 안에서 account값이 할당이 되고  그 값을 리턴하는데 Future<string>타입이다.

   -> 리턴타입이 Future<string>라는 것은 일정 시간 후에 Future타입을 리턴하는데 이는 문자열을 의미/ 즉, 비동기 처리를 진행하고 일정 시간 후 string을 리턴한다는 뜻

 - Future<string>타입을 리턴하는 acessData함수는 결국 showData함수에서 호출되므로 showData함수도 비동기 처리를 해줘야 한다.

import 'dart:io';

void main(){
  showData();
}

void showData() async{
  startTask();
  String account = await acessData();
  fetchData(account);
}

void startTask(){
  String info1 = '요청수행 시작';
  print(info1);
}

Future<String> acessData() async{
  String account="";

  Duration time = Duration(seconds: 3);

  if(time.inSeconds>2){
    //async로 처리되는 부분
    await Future.delayed(time, (){
      account = "8,500만원";
      print(account);
    });
  }else{
    String info2 = "데이터를 가져왔습니다.";
    print(info2);
  }
  return account;
}

void fetchData(String account){
  String info3 = '잔액은 $account원 입니다.';
  print(info3);
}

코드 리팩토링이란?

코드를 유지 보수하기 좋게 바꾸는 것

가독성도 높일 수 있고 불필요한 중복을 피할 수 있다.
이는 결국 다른 사람과의 협업에도 도움이 된다.

 

참고: https://velog.io/@qkrtnfks128/Flutter-%EC%BD%94%EB%93%9C-%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81refactoring

 

[Flutter] 코드 리팩토링(refactoring)

코드를 간결하게~~!!

velog.io

 

 

 

로그인 페이지를 통한 코드 리팩토링

main.dart

import 'package:flutter/material.dart';
import 'login_app/login.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Firebase login app',
      home: LogIn(),
    );
  }
}

 

my_button.dart

유사한 모양의 버튼을 여러개 사용하는 상황에서 

MyButton이라는 클래스를 만들어서 변경요소인 image, text, color, radius, VoidCallback 함수 를 매개변수로 생성자를 호출하면 동일한 버튼을 찍어낼 수 있도록 함.

required 문법에 대한 이해 필요

import 'package:coderefactoring/login_app/login.dart';
import 'package:flutter/material.dart';

class MyButton extends StatelessWidget {
  MyButton({Key? key, required this.image, required this.text, required this.color, required this.radius, required this.onPressed}) : super(key: key);

  final Widget image;
  final Widget text;
  final Color color;
  final double radius;
  final VoidCallback onPressed;

  @override
  Widget build(BuildContext context) {

    return ButtonTheme(
      height: 50.0,
      child: ElevatedButton(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            image,
            text,
            Opacity(
              opacity: 0.0,
              child: Image.asset('images/glogo.png'),
            ),
          ],
        ),
        style: ElevatedButton.styleFrom(
            backgroundColor: color
        ),
        onPressed: onPressed,
      ),
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.all(
          Radius.circular(radius),
        ),
      ),
    );
  }
}

 

 

login.dart

MyButton객체를 이용해서 버튼을 쉽게 생성

import 'package:coderefactoring/my_button/my_button.dart';
import 'package:flutter/material.dart';

class LogIn extends StatelessWidget {
  const LogIn({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.blue,
        title: Text(
          'Sign In',
          style: TextStyle(color: Colors.white),
        ),
        centerTitle: true,
        elevation: 0.2,
      ),
      body: buildButton(),
    );
  }

  Widget buildButton() {
    return Padding(
      padding: EdgeInsets.all(16.0),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          MyButton(
              image: Image.asset('images/glogo.png'),
              text: Text(
                'Login with Google',
                style: TextStyle(color: Colors.black87, fontSize: 15.0),
              ),
              color: Colors.white,
              radius: 4.0,
              onPressed: () {}),
          SizedBox(
            height: 10.0,
          ),
          MyButton(
              image: Image.asset('images/flogo.png'),
              text: Text(
                'Login with Facebook',
                style: TextStyle(color: Colors.white, fontSize: 15.0),
              ),
              color: Color(0xFF334D92),
              radius: 4.0,
              onPressed: () {}),
          SizedBox(
            height: 10.0,
          ),
          MyButton(
              image: Icon(
                Icons.mail,
                color: Colors.white,
              ),
              text: Text(
                'Login with Email',
                style: TextStyle(color: Colors.white, fontSize: 15.0),
              ),
              radius: 4.0,
              color: Colors.green,
              onPressed: () {},
          ),

          SizedBox(
            height: 10.0,
          ),
        ],
      ),
    );
  }
}

 

 

 

1. Image.asset('경로')

2. Image(image: AssetImage('경로')

 

'플로터(Flutter) > CheetSheet' 카테고리의 다른 글

focus  (0) 2023.01.17
Flutter Snackbar사용법  (0) 2023.01.17

 

focus

 

참고

https://dev-gold.tistory.com/114

 

[Flutter]Focus and text fields 포커스 및 텍스트 필드

텍스트 필드가 선택되고 입력을 받을 수 있을 때, 포커스를 갖는다고 합니다 일반적으로, 사용자는 탭하여 텍스트 필드에 포커스를 이동시키고, 개발자는 아래 레시피에 설명되어있는 방식으로

dev-gold.tistory.com

https://velog.io/@sunwonsw95/Flutter-Focus-widget

 

[Flutter] Focus widget

모바일 앱의 다양한 입력필드를 보면 입력 필드에 포커스가 맞춰져 있는 동안 입력 필드 내 특정 아이콘이나 버튼, 텍스트가 활성화 되는 경우가 상당히 많다.나 역시 플러터의 TextFormField위젯을

velog.io

 

'플로터(Flutter) > CheetSheet' 카테고리의 다른 글

이미지 처리  (0) 2023.01.17
Flutter Snackbar사용법  (0) 2023.01.17

+ Recent posts