Flutter & Dart

[Flutter] 플러터에 대해 알아보자

코딩하는후운 2022. 10. 20. 15:45
반응형

Flutter 간단 정리

플러터 레이아웃 참고 사이트

안드로이드와 ios모바일 애플리케이션을 One Source로 개발할 수 있는 UI프레임워크

-플러터는 구글에서 만들었습니다.
-플러터 공식 홈페이지 flutter.dev
-플러터는 다트(Dart)라는 언어로 개발
-플러터 개발 시작은 안드로이드 스튜디오를 권장.


플러터 설치하기
1)안드로이드 스튜디오 설치
2)flutter-sdk를 설치합니다.
3)안드로이드 스튜디오에서 (flutter plugin)을 설치합니다.


변수 - 타입 지정, 타입 추론
다트는 타입을 정할 수도 있고, 안 정할 수도 있다. 타입을 정하지 않으면 컴파일할 때 타입이 정해진다.(타입 추론)
다만 한번 정한 타입을 나중에 바꿀 수는 없다.(type-safe)
DART - 타입 지정 or 타입 추론

int num = 10;
double height = 175.3;
String name = "Mike";
var world = "Hello world"; //동적 타입, 타입 추론
var age = 78;




배열 대신에 리스트
자바에선 배열과 리스트를 구분하지만 다트는 리스트만 사용하기에 좀 더 편하게 데이터를 다룰 수 있다.
DART

var numbers = [10,20,30];
var countries = ["USA", "JAPAN", "KOREA", 10];
print(countries[0]);


함수

자바스크립트랑 비슷한 측면이 많다. 타입을 명시해도 되고, 안 해도 된다.
DART-타입 추론
combine(a,b){
	return a+b
}

var result = combine(10, 20);
print(result);

var word = combine("hello", "world");
print(word);

DART - 타입 지정
int add(int a, int b){
	return a+b;
}

int sum = add(15, 25);
print(sum);

Effective Dart에서는 타입을 지정하는 걸 권장하고 있다.


if, For, while, Case == 자바와 같음.


Class - 이름 있는 생성자(Named Constructor)
DART
class Point{
    num x;
    num y;

Point(num x, num y){
    this.x = x;
    this.y = y;
}

Point.origin(){
    x = 0;
    y = 0;
}
}

1가지를 제외하고는 자바와 큰 차이가 없다. Point.origin()가 있냐 없냐의 차이다.
Point.origin()은 대체 어떤 역할을 하는걸까?
Point.origin()은 이름 있는 생성자로 x,y를 0으로 초기화 하는 역할을 한다.

Point p = Point(10, 30);
print(p.x); //10

var origin = Point.origin();
print(origin.x); //0

이처럼 이름 있는 생성자는 여러 생성자를 만들거나 생성자 내에서 값 체크, 파싱 등 각종 작업을 할 때 쓰인다.

Point.fromJson(Map<String, num> json)
: x = json['x'],
  y = json['y'] {
  print('In Point.fromJson(): ($x, $y)');
}
이름 있는 생성자를 만들고 실행 해보자.객체를 만들때 json 파싱을 이어서 한다.
void main(){
    Map<String, int> json = Map();
    json['x'] = 15;
    json['y'] = 20;

    var point = Point.fromJson(json);
    print("point x :  ${point.x}, y: ${point.y}"); //x:15, y:20 출력
}



Factory

 

팩토리 생성자는 팩토리 패턴을 쉽게 쓰기위해 만들어졌다.
자바에서는 팩토리 패턴을 쓰려면 팩토리 클래스를 따로 만들어줘야한다.
다트에서는 기본 생성자와 같이 쓸 수 있다.

Java - 로봇 클래스 선언, 각 로봇을 담당.
public abstract class Robot{
    abstract String getName();
    abstract String command();
}

public class CleanRobot extends Robot{
    @Override
    String getName(){
        return "Clean";
    }

    @Override
    String command(){
    	System.out.println("clean a room");
        return "clean a room";
    }
}

    public class warRobot extends Robot{
        @Override
        String getName(){
            retunrn "war";
        }

        @Override
        String command(){
            System.out.println("declare war");
            return "declar war";
        }
    }
로봇 클래스를 만들었으면 팩토리 클래스를 만들어보자. 로봇 이름에 따라 다른클래스를 만들어준다.
Java - 팩토리 클래스, 모든 로봇의 생산을 담당.
public class RobotFactory{
    Robot createRobot(String name){
        switch(name){
            case "Clean":
            	return new CleanRobot();
            case "War":
                return new WarRobot();
            }
        return null;
    }
}



Java - 실행

RobotFactory factory = new RobotFactory();
Robot r1 = factory.createRobot("Android");
r1.command();


DART - 로봇 클래스, 팩토리 생성자 사용
abstract class Robot{
    Robot.create();

    factory Robot(RobotType type){ //팩토리 생성자
        switch(type){
            case RobotType.Clean:
                return CleanRobot();
            case RobotType.War:
                return WarRobot();
        }
    }

    String getName();
    String command();

    enum RobotType{
        Clean, War
    }
}



DART - 자식 클래스들

class CleanRobot extends Robot{
    CleanRobot(): super.create();

    @Override
    String getName(){
    	return "Clean";
    }

    @Override
    String command(){
        print("clean a room");
        return "clean a room";
    }
}



DART - 실행

Robot r1 = Robot(RobotType.Clean);
r1.command();



-Map
자바와 다트의 맵은 조금 다르다.
자바의 맵은 자유롭게 수정이 가능, 다트는 수정 가능하게 쓸 수도, 불가능하게 쓸 수도 있다.

Java

Map<String, Integer> map = new HashMap<>();
map.put("height", 175);
map.put("height", 180);



다트는 2가지 방법으로 맵을 관리한다.
키가 있어도 값을 추가하거나(수정 불가),
-map[key] = value
키가 없을 때만 값을 추가한다(수정 가능)
-putIfAbsent사용

DART

Map<String, int> map = Map<String, int>();
map.putIfAbsent("height", () => 175); //키가 없을 때만 값을 추가
map.putIfAbsent("height", () => 180);

print(map["height"]); //175 출력

map["height"] = 190; //이미 키가 있어도 값을 추가
print(map["height"]); //190 출력



-Concurrency(동시성) - isolate, Thread
다트는 싱글 스레드이다. 여러 스레드를 만들 수 없다.
다트에선 Isolate를 만들어 병렬 처리를 한다.
스레드 안에 Isolate가 여럿 있는걸 상상하면 된다.

Isolate는 분리된 작업 단위이다.
각각의 메모리 힙이 있다.lock을 걸 수 없기에 경쟁 상태나 데드락이 발생하지 않는다.

가장 기본이 되는 Isolate는 main isolate이다. 다트 런타임에 의해 만들어진다.
main isolate는 필요에 따라 Isolate를 만들어 쓴다.(스폰 spawn)

DART - Isolate만들기(스폰하기)

void main(){
    Isolate.spawn(sendMessage, 'Hello');
    Isolate.spawn(sendMessage, 'Greetings');
    Isolate.spawn(sendMessage, 'welcome');
}

void sendMessage(var message){
	print('This is a ${message}');
}



3개의 isolate가 만들어진다.
순서대로 실행되지는 않는다.


비동기처리 - Future, Async, Await
퓨처(Future, 미래)란 객체를 쓴다.

Java
//Java 8 - async 함수를 사용해 비동기 처리를 했다.

CompletableFuture.runAsync(() ->{
	System.out.println("Run async in completableFuture");
});



//RxJava - 새 스레드를 생성해서 비동기 처리를 했다.

Observable.just(1,2,3,4,5)
    .subscribeOn(Schedulers.io())
    .subscribe( numbers ->{
        System.out.println(numbers);
    });



다트의 비동기는 Future, await, async로 구성되어 있다.
Future: 바로 끝나지 않는 작업을 할 때 쓰인다. 일반적인 함수는 결과를 리턴하지만, 비동기 함수는 Future를 리턴한다.
await:비동기 처리가 끝날 때까지 기다린다는 의미다. 다른 작업을 진행하지 않는다. Future의 작업을 완료하고 다음 작업을 할 때 쓰인다.
async:비동기 처리를 하겠단 선언이다. await는 async와 항상 함께 쓰인다.


DART - 1.Future만 써보기 - second()함수만 2초 뒤에 실행된다.

void main(){
    first();
    second();
    third();
}

void first(){
	print("first");
}

void second() async{ //async는 비동기 처리하라는 의미.
    Future.delayed(Duration(seconds: 2), (){ //2초 딜레이
    	print("Second");
    });
}

void third(){
	print("third");
}



DART - 2.Future와 따로 실행해 보기

void second() async{
    Future.delayed(Duration(seconds: 2), (){
    	print("Future inside");
    })
	print("Second");
}



DART - 3. await 사용 - 퓨처가 완료될때까지 기다림.

void second() async{
    await Future.delayed(Duration(seconds: 2), (){
    	print("future inside");
    });
    print("Second");
}



await를 쓰면 Future의 작업이 끝날 때까지 기다렸다가 다음으로 넘어간다.
그렇다면 중간에 멈추지 않고 Future값을 처리하려면 어떻게 해야 할까?
then()을 써주면 된다.

void main(){
    print("BEFORE");
    readFileAsync().then((data) => print(data));
    print("AFTER");
}

Future readFileAsync() async{
	return await File("file.json").readAsString();
}



반면 await를 쓰면 파일 읽기를 완료할때까지 다른작업을 하지 않는다.
print(await readFileAsync());

await을 쓰면 간단히 비동기 처리를 할 수 있지만, 메인함수에서 쓰는건 주의해야함.


isolate vs Future
Isolate:병렬 작업을 할 수 있게 해준다. 멀티 스레드와 유사하며 여러 Isolate를 만들어서 작업을 할 수 있다.
Future:비동기 처리를 하지만, 보통 한 스레드내에서 작업이 이루어진다.



참조 :

https://software-creator.tistory.com/5?category=681555
https://software-creator.tistory.com/10

 

반응형

'Flutter & Dart' 카테고리의 다른 글

[Flutter] Screen Naviation | 화면(라우트)간 이동  (0) 2022.10.22
플러터 튜토리얼 앱  (0) 2022.10.22
플러터 커스텀 위젯 추가  (0) 2022.10.22
플러터 스트림  (0) 2022.10.22
다트 기본 문법  (0) 2022.10.20