app개발/flutter

[Flutter] Dart언어란?

pa_songsong 2021. 11. 6. 17:40

Flutter 앱을 간단하게 만들어 본 경험은 있으나 Dart와 Flutter에 대한 기본은 제대로 짚고 넘어가기 위해서 도서관에서 책을 빌려 읽고 중요 부분을 정리해 보았습니다.

참고한 책은 플러터 앱 프로그래밍입니다. 이 책을 선택한 이유는 총 2가지입니다.

 

첫번째는, 기본적으로 앱을 만들어 보았으나 Flutter의 전반적인 기초는 다지면서 개발해나가고 싶었습니다.

두번째는, 오픈 API 활용법, 파이어베이스 등의 부가적인 기능들을 사용하는 방법을 익혀보고 싶었기 때문입니다.

 

0. Dart(이하 다트)언어의 8가지 특징

  • 다트는 main()함수로 시작
  • 다트는 어디서나 변수 선언하고 사용 가능
  • 다트는 모든 변수가 객체. 모든 객체는 Object 클래스를 상속받음
  • 다트는 자료형이 엄격한 언어. 여러 자료형 허용하려면 dynamic 타입 이용.
  • 다트는 제네릭 타입 이용 가능
  • 다트는 public, protected 같은 키워드가 없음. 외부로 노출하고 싶지 않을 시 변수나 함수 이름 앞에 언더스코어( _ ) 로 표시
  • 변수나 함수의 시작은 _ 또는 문자열로 시작. 그 이후에 숫자 입력 가능
  • 삼항 연산자 사용 가능.

 

1. 간단한 코드

자바를 이미 배워서 그런지 처음에 시작할 때 코드 이해가 어렵지는 않았습니다.

printInteger(int Num){
	print('The number is $Num.');
}

main(){
	var number = 42;
    printInteger(number);
}

실행 결과 (https://dartpad.dartlang.org/?null_safety=true)

  • 다트 주요 자료형
구분 자료형 설명
숫자 int 정수형 숫자
double 실수형 숫자
num 정수 or 실수형 숫자
문자열 String 텍스트 기반 문자
불리언 bool True 나 False
자료형 추론 var 입력받은 값에 따라 자료형 결정.
한번 결정시 변경 불가
dynamic 입력받은 값에 따라 자료형 결정.
다른 변수 입력시 자료형 변경 가능

 

2. 비동기 처리 방식

다트는 비동기 처리를 지원하는 언어입니다.

비동기(asynchronous)는 언제 끝날지 모르는 작업을 기다리지 않고 다음 작업을 처리하게 하는 것을 의미합니다.

일반적으로 네트워크에서 데이터를 가져오거나 데이터베이스 쓰기, 파일 읽기 등의 작업은 비동기로 처리합니다.

동기 방식은 하나의 일이 마칠때까지 기다려야하나 비동기 방식은 하나가 끝날때 까지 기다리지않고 병렬적으로 처리합니다. 동시에 처리하는 것처럼 보이게 되어 총 처리시간이 동기 방식보다 줄어듭니다.

1. 비동기 프로세스 작동 방식 

async 와 await 키워드로 비동기 프로세스를 만듭니다.

Future와 async를 붙인다는 것은 비동기 함수로 만들겠다는 뜻입니다.

이렇게 비동기로 만든 checkVersion() 내부에 await을 사용했습니다.

이는 await이 붙은 함수를 따로 비동기로 처리한 다음 그 결과는 Future 클래스에 저장해 둘 테니 main()의 나머지 코드를 모두 실행하라는 뜻입니다. 즉, await 키워드는 처리를 완료하고 결과를 반환할 때까지 이후 코드의 처리를 멈춥니다. 비동기 함수에서 어떤 결괏값이 필요하다면 해당 코드를 await로 지정할 수 있고 이는 네트워크 지연등으로 제대로 된 값을 반환받지 못한 채 이후 과정이 실행되는 것을 방지할 수 있습니다.

//예시 코드
void main(){
	checkVersion();
    print('end process');
}
Future checkVersion() async{
	var version = await lookUpVersion();
    print(version);
}

int lookUpVersion(){
	return 12;
}​

결과는 아래와 같이 end process가 먼저나오고 12가 나오게 됩니다. 동기 프로세스는 checkVersion 함수의 결과인 12가 나올때까지 기다리고나서 end process 가 출력되지만 비동기는 checkVersion 함수가 끝날때까지 기다리지 않습니다.

2. 비동기 함수가 반환하는 값 활용

//then() 함수 사용법
void main() async{
	await getVersionName().then((value) =>{
    	print(value)
    });
    print('end process');
}

Future<String> getVersionName() async{
	var versionName = await lookUpVersionName();
    return versionName;
}

String lookUpVersionName(){
	return 'hello';
}

결과는 아래 콘솔창 내용과 같습니다. getVersionName()의 반환 값으로 hello를 리턴 후 end process를 출력합니다. 

then()외에 error()도 있어서 이를 사용해 예외를 처리할 수 있습니다.

3. 다트와 스레드

다트는 하나의 스레드로 동작하는 프로그래밍 언어입니다.

void main(){
	printOne();
    printTwo();
    printThree();
}

void printOne(){
	print('One');
}

void printThree(){
	print('Three');
}

void printTwo() async{
	Future.delayed(Duration(seconds: 1), (){
    	print('Future');
    });
    print('Two');
}

결과

printTwo()를 수정해보겠습니다.

void main(){
	printOne();
    printTwo();
    printThree();
}

void printOne(){
	print('One');
}

void printThree(){
	print('Three');
}

void printTwo() async{
	//await를 붙이고 second를 2로 늘렸습니다
    await Future.delayed(Duration(seconds: 2), (){
    	print('Future');
    });
    print('Two');
}

결과가 달라졌습니다. await 키워드에 따라 Future.delayed() 코드 이후의 실행이 멈추었기 때문입니다.

 

3. JSON 데이터 주고받기

애플리케이션과 서버와의 통신에서 가장 많이 쓰는 형식이 JSON입니다.

  • JSON 데이터 디코딩 예

jsonDecode() 함수는 JSON 형태의 데이터를 dynamic 형식의 리스트로 변환해서 반환해줍니다.

scores is List는 scores 변수가 리스트가 아니면 False, 맞으면 True를 반환합니다.

import 'dart:convert';

void main(){
  var jsonString = '''[
    {"score": 40},
    {"score": 80}
  ]
  ''';
  var scores = jsonDecode(jsonString);
  print(scores is List);
  var firstScore = scores[0];
  print(firstScore is Map);
  print(firstScore['score'] == 40);
}

결과

  • JSON 데이터 인코딩 예

jsonText의 값이 제대로 출력된 것을 확인할 수 있습니다.

import 'dart:convert';

void main(){
  var scores = [
    {"score":40},
    {"score":80},
    {"score":100,"overtime":true,"special_guest":null}
  ];
  
  var jsonText = jsonEncode(scores);
  print(jsonText ==
       '[{"score":40},{"score":80},'
    '{"score":100,"overtime":true,"special_guest":null}]');
}

결과

4. 스트림 통신하기

애플리케이션 개발 시 데이터를 순서대로 주고받아야 할 때가 있습니다. 순서를 보장받고 싶을 때 스트림(stream)을 이요합니다. 이를 이용하여 데이터를 차례대로 주고받는 코드를 작성할 수 있습니다.

  • 스트림 통신 예시

main()에서 먼저 countStream(10)을 호출합니다. 이 countStream 함수는 async*와 yield를 이용해 비동기 함수로 작성되었습니다. async*은 앞으로 yield를 이용해 지속적으로 데이터를 전달하겠다는 의미입니다.

return은 한 번 반환하면 함수가 끝나지만 yield는 반환 후에도 계속 함수를 유지합니다.

이렇게 yield값을 인자로 sumStream()을 호출하면 이 값이 전달될 때마다 sum 에 누적해서 반환해줍니다. 

import 'dart:async';

Future<int> sumStream(Stream<int> stream) async{
  var sum = 0;
  await for (var value in stream){
    print('sumStream : $value');
    sum += value;
  }
  return sum;
}


Stream<int> countStream(int to) async*{
  for(int i = 1; i<=to; i++){
    print('countStream : $i');
    yield i;
  }
}

main() async{
  var stream = countStream(10);
  var sum = await sumStream(stream);
  print(sum);
}

결과

  • then() 함수로 스트림 코드 작성한 예

아래와 같이 작성하면 오류가 발생하는데 그 이유는 스트림을 통해 데이터를 사용하면 데이터는 사라지기 때문입니다.

따라서 두번째 코드처럼 한번만 실행하도록 변경해야 합니다.

<여러번 실행한 코드>

main(){
  var stream = Stream.fromIterable([1,2,3,4,5]);
  
  //가장 앞의 데이터 결과 : 1
  stream.first.then((value) => print('first: $value'));
  //가장 마지막 데이터 결과 : 5
  stream.last.then((value) => print('last: $value'));
  //현재 스트림 비어있는지 확인: false
  stream.isEmpty.then((value) => print('isEmpty: $value'));
  //전체 길이 : 5
  stream.length.then((value) => print('length: $value'));
}

<결과>

<한번만 실행한 코드>

main(){
  var stream = Stream.fromIterable([1,2,3,4,5]);
  
  //가장 앞의 데이터 결과 : 1
  stream.first.then((value) => print('first: $value'));
}

<결과>

  • 스트림 사용 할 때?

스트림은 실시간으로 서버 살피다가 서버에서 데이터 변경되어 화면 새로고침하지 않더라도 자동으로 변경된 데이터가 반영되어야 할 때 사용할 수 있습니다.

5. 간단한 다트 프로그램

  • 클래스 구현하기
void main(){
 Phone iPhone = Phone(1000000, 'purple','13pro');
 Phone galaxyPhone = Phone(1000000, 'red','21note');
  
 iPhone.salePhone();
 galaxyPhone.salePhone();
 print(galaxyPhone.price);
}

class Phone{
  int price = 0;
  String color = '';
  String series = '';
  
  Phone(int price, String color, String series){
    this.price = price;
    this. color = color;
    this.series = series;
  }
  
  int salePhone(){
    price = price * 0.9 as int;
    return price;
  }
}

갤럭시폰 세일 후 핸드폰 값 출력

'app개발 > flutter' 카테고리의 다른 글

[Flutter] Flutter 위젯 사용법  (0) 2021.11.06
[Flutter] 위젯 생명주기  (0) 2021.11.06
[flutter] StatefulBuilder  (0) 2021.09.19
flutter UI 개발하면서 막혔던 것들 정리 1  (0) 2021.08.31
[flutter] 개발환경 세팅  (0) 2021.05.18