'모바일 앱개발'에 해당되는 글 2건

  1. 2023.07.04 Do it! 플러터 내부구조, 생명주기 알아보기
  2. 2023.07.03 Do it! 플러터 개념부터, Dart 기본까지

실전코드로 배우는 플러터 기본과 활용

Do it! 플러터 앱프로그래밍

어제는 Flutter의 등장배경과 Flutter에서 사용하는 언어인 Dart의 특징에 대해 간략히 배웠습니다. 

오늘은 플러터의 내부 구조(간단한 샘플코딩)와 위젯의 생명주기에 대해 공부하고자 합니다. 위젯의 생명주기는 안드로이드 액티비티의 생명주기와 비슷하다고 생각하시면 됩니다.

폴더 및 주요 파일 안내

Flutter 프로젝트 구조. 시작 파일은 lib>main.dart

폴더 내용 비고
android 안드로이드 프로젝트 관련 파일 안드로이드 스튜디오로 실행 가능
ios iOS 프로젝트 관련 파일 엑스코드로 실행 가능(맥 전용)
lib 플러터 앱 개발을 위한 다트 파일 플러터 SDK 설치 필요
test 플러터 앱 개발 중 테스트 파일 테스트 편의성 제공
파일 내용 비고
pubspec.yaml 패키지, 이미지, 폰트 등 asset 설정 직접 관리
README.md 프로젝트 소개
.gitignore git에 커밋, 푸시 등 소스 코드를 업로드할 때 필요 없는 파일 기록
서버 주요 정보, 운영/테스트 구분에 따른 배포시 배제해야 할 파일들 명시
.metadata 플러터 SDK 정보 자동 관리
.packages 플러터 SDK에 사용할 기본 패키지 경로
first_flutter_app.iml 파일이 자동으로 생성될때 만들어지는 폴더 위치
pubspec.lock pubspec.yaml 파일에 적용된 패키지 위치

* 플러터는 위젯 기반으로 개발하며, 위젯은 클래스로 정의하여 상속 개념이 존재합니다. 텍스트박스, 이미지, 버튼 모두가 위젯 클래스로 변경이 필요하면, 상속받아 필요한 속성만 수정하면 됩니다. 위젯은 크게 2가지 나눕니다. 상태 고정(statless, 화면에 보이기 위해 로딩한 순간 상태감시를 하지 않아 변화가 없는 위젯)과 상태변경(statefull, 동적 위젯으로 상태를 감시하다 알맞게 화면 변경) 입니다. 따라서 화면 변경이 필요한 경우, statefull 위젯에 코딩해야 합니다. 

교제에 나와 있는대로, 버튼 클릭시 글씨와 버튼색이 변하는 것을 statless위젯(클래스)에 개발하면 아무런 변화가 없지만, statefull위젯에 개발하면 화면이 변하는 것을 확인할 수 있습니다.

추가로 책의 예제를 따라 코딩해보면, 플러터 버전에 따라 폐기된 위젯들이 있어 아래와 같이 소스를 수정해서 코딩해야 합니다. 

// 교제 소스 //
child: RaisedButton (
            child: Text('$test'),
            color: _color,
            onPressed: () {
              if (test == 'hello') {
                setState(() {
                  test = 'Flutter';
                  _color = Colors.amber;
                });
              } else {
                setState(() {
                  test = 'hello';
                  _color = Colors.blue;
                });
              }
            },
          ),
// 수정 RaisedButton -> ElevatedButton
// 수정 style: ElevatedButton.styleFrom 이용
child: ElevatedButton (
            child: Text('$test'),
            style: ElevatedButton.styleFrom(
              primary: _color,
            ),
            onPressed: () {
              if (test == 'hello') {
                setState(() {
                  test = 'Flutter';
                  _color = Colors.amber;
                });
              } else {
                setState(() {
                  test = 'hello';
                  _color = Colors.blue;
                });
              }
            },
          ),

* visualDensity 속성은 앱이 모바일, 웹, 데스크톱, 맥 등 어떤 플랫폼에서도 자연스럽게 보이도록 지원

위젯의 생명 주기 이해

class MyHomePage extends StatefulWidget {
	@override
    _MyHomePageState createState() => new _MyHomePageState();
}

State와 StatefulWidget 클래스를 나눈 이유는 성능 때문입니다. State 클래스가 무겁다 보니, StatefulWidget에서 감시하고 있다가 상태 변경 신호가 오면, State클래스로 화면을 갱신하도록 합니다. 만약 StatefulWidget에서 바로 갱신하면, 화면이 종료되더라도 할당받은 메모리를 바로 반환하지 않기 때문에 두개는 분리한 것입니다. 

호출순서 생명주기 내용
1 createState() 처음 스테이트풀을 시작할 때 호출
2 mounted == true createState() 함수가 호출되면 mounted 는 true
3 initState() State에서 제일 먼저 실행되는 함수. State 생성 후 한번만 호출
4 didChangeDependecies() initState() 호출후에 호출되는 함수
5 build() 위젯을 렌더링하는 함수. 위젯을 반환(=화면에 표시)
6 didUpdateWidget() 위젯을 변경해야 할 때 호출하는 함수
7 setState() 데이터가 변경되었음을 알리는 함수. 변경된 데이터를 UI에 적용하기 위해 필요
8 deactivate() State가 제거될 때 호출
9 dispose() State가 완전히 제거되었을 때 호출
10 mounted == false 모든 프로세스가 종료된 후 mounted가 falsed가 됨

 

요약(프로젝트 구조, 위젯 생애주기...)
• 프로젝트 주요폴더, 파일에 대해 확인
• createState(), initState(), build(), setState(), dispose() 등 생애주기 과정에 log, 데이터 처리 등 수행

 

Posted by 목표를 가지고 달린다
,

실전코드로 배우는 플러터 기본과 활용

Do it! 플러터 앱프로그래밍

오픈API활용, 파이어베이스, 구글맵까지 배울 수 있는 크로스 플랫폼. Flutter에 입문하기 위해 위 플러터 앱프로그래밍 책을 가지고 3주 이내로 공부하려고 합니다. 배우고 정리해서 최종적으로 간단하고 필요한 앱들이 3개 정도 만들 수 있는 수준까지 올라가는 것이 목표입니다. 코틀린이 발전하기 전, 안드로이드 스튜디오에서 Java로 만들때는 디자인이 너무 어려워서 포기도 했었는데, Flutter는 디자인 기반이라 개발자도 쉽게 괜찮은 수준으로 외관을 만들 수 있다고 해서 도전해 보려고 합니다. 

플러터 등장 배경

모바일OS는 안드로이드와 iOS가 대부분 점유하고 있습니다. 애플은 오브젝트-C에서 스위프트(Swift) 언어를를 추가 지원하고 있으며, 안드로이드는 자바에서 Kotlin을 밀고 있습니다.(오라클에서 Java 이용에 대한 라이선스 비용 이슈. 아직 Java기반의 앱들이 많아 Kotlin으로 모두 대체되는데는 시간이 상당 필요) 이런 각 모바일 운영체제에 맞는 언어로 개발한 앱을 네이티브 앱(native app)이라고 합니다.

최근 전세계 iOS와 안드로이드의 시장점유율. 출처 : statista

하지만, 두 운영체제의 언어로 개발하면 2source 1서비스라서 관리가 어려워, 웹앱이나 하이브리드앱이 등장하였습니다. 최근 Progressive 웹앱에서는 알림도 받을 수 있다고합니다. 하지만 이런 하이브리드 앱은 속도 측면에서 느리다는 단점이 있습니다. 

그래서 나왔던게 페이스북의 리액트, 구글의 플러터입니다.

구분 리액트 네이티브 플러터
개발주체 페이스북 구글
언어 자바스크립트 다트
성능 빠르지만, 네이티브 앱보단 느림 네이티브 앱에 근접한 속도
학습 곡선 높음(네이티브 앱 개발자 수준) 낮음(네이티브 앱 개발자 수준)
대표 앱 페이스북, 인스타그램, 핀터레스트, 토스 알리바바, 구글애드센스, 네이버 지식in
장점  웹 개발자의 접근성(코딩을 잘해야 함)
 많은 패키지 이용 가능
 다양한 위젯(디자인 구성이 편함)
 강력한  애니메이션 등
단점 • 기본 위젯이 부족해 커스텀해 사용
 안드로이드/iOS 네이티브 위젯을 이용하기에 OS 판올림에 따른 업데이트 필요
 블루투스 등 네이티브 커스텀해 통신하는 부분 개발이 어려움
 플로터 SDK로 앱 크기가 큼(네이티브 대비)
 업데이트 주기가 빠름(책, 인터넷의 예제에 deprecated(폐기) 된 항목들이 종종 있음)

개발해보면 아시겠지만, hot reload 기능으로 소스 수정하면 별도 빌드과정없이 바로 결과 화면(가상디바이스화면, 웹화면)에 바로 표시해 주어 개발 효율이 높고, 앱을 만들더라도 웹화면에서 개발 결과를 확인해도 됩니다.

개발 환경 구축

안드로이드 스튜디오를 설치한 후, 플러터 SDK를 설치합니다. (https://docs.flutter.dev/get-started/install

정상적으로 설치가 되었다면, CMD창에서 flutter 폴더로 가셔서 flutter doctor 명령어로 개발 환경을 점검할 수있습니다.

flutter 개발환경 점검을 위해 flutter doctor 실행 결과 화면

그리고 안드로이드 스튜디오로 "Create New Flutter Project"를 생성하면서, "Flutter" 플로그인도 설치합니다.

Dart 핵심 요약 
  • 다트 언어의 6가지 특징
  • 비동기 처리 방식
  • JSON 데이터 처리 방식
  • 스트림 통신(순서 보장)

다트언어의 6가지 특징

  1. main()함수로 시작
  2. 변수는 어디에서나 선언 및 사용 가능
  3. 자료형이 엄격하여 선언한 타입외 다른 유형의 값 입력 불가. 선언하고 나중에 타입을 정하려면 var를 이용하고, 동일 변수에 여러 자료형을 허용하려면 dynamic 타입으로 이용 가능
  4. 제네릭 타입 이용 개발 가능 List<int>, List<dynamic> 등
  5. public, protected 같은 키워드 없음. 다만, 외부로 노출하고 싶지 안핟면, 변수나 함수 앞에 언드스코어( _ )를 이용해 표시. _hiddenValue, _hideValue
  6. 삼항 연산자를 자주 사용 (예 : var visibility = isPublic ? 'public' : 'private';)

비동기 처리 방식

다트는 async와 await 키워드를 이용해서 비동기 처리를 구현합니다.

  1. 함수 이름 뒤, 본문이 시작하는 중괄호 { 앞에 async 키워드를 붙여 비동기를 선언
  2. 비동기 함수 안에 언제 끝날지 모르는 작업 앞에 await 키워드를 붙임
  3. 2번 작업을 마친 결과를 받기 위해 비동기 함수 이름 앞에 Future(값이 여러개면 Stream) 클래스를 지정
void main() {
    checkVersion();
    print('end process');
}

Future checkVersion() async {
    var version = await lookUpVersion();
    print(version);
}

int lookUpVersion() {
    return 12;
}

#실행결과#
end process
12

비동기 함수가 반환하는 값을 처리하면, then() 함수를 이용

void main() async {
	await getVersionName().then( (value) => {
    	print(value)
    });
    print('end process');
}

다트는 단일 스레드로 동작하는 프로그래밍 언어

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

JSON 데이터 주고 받기

Convert라는 라이브러리를 활용하여 쉽게 이용 가능하며, jsonDecode 반대는 jsonEncode() 함수입니다. 

import 'dart:convert';

void main () {
    var jsonString = '''
    [
    	{"lotto" : 5},
        {"lotto" : 15},
     ]
     ''';
     
	var lottos = jsonDecode(jsonString);
    print (lottos is List); // true 출력
    var lottoOne = lottos[0];
    print(lottoOne is Map);  // true 출력
    print(lottoOne['lotto'] == 5); //true
}

스트림 통신하기 

데이터를 주고 받을 때 순서 보장이 필요하다면, 스트림(stream)을 이용합니다. return은 한번 반환하면 함수가 종료되지만, yield 키워드는 반환 후에도 계속 함수를 유지합니다.(계속 반환) 그리고 async* 명령어는 yield를 이용해서 지속적으로 데이터를 전달하겠다는 의미입니다. 

import 'dart:async';

Future<int> sumStream(Stream<int> stream) async {
    var sum = 0;
    await for (var value in stream) {
    	print ('sumSteam : $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() 함수를 이용할 수있습니다. 다만, 스트림은 소모하면 사라지므로, first, last, length 등 한번만 실행해야 할 경우 이용합니다. 동일 스트림에 first, last를 같이 사용한다면 오류가 발생할 수 있습니다. 

main() {
    var stream = Stream.fromIterable([1,2,3,4,5]);
    
    //첫번째 값 출력
    stream.first.then((value)=> print('first: $value'));
    //마지막 값 출력
    stream.last.then((value)=> print('last: $value'));
    //스트림 비었는지 출력
    stream.isEmpty.then((value)=> print('isEmpty: $value'));
    //스트림 길이 출력
    stream.length.then((value)=> print('length: $value'));
요약(플러터 시작, 다트를 알면..)
• Flutter는 iOS, 안드로이드용 앱을 한번에 개발할 수 있는 개발 플랫폼
• Dart의 특징
 - proteced처럼 하려면 변수와 함수명 앞에 언드스코어( _ ) 추가
 - async-await-Future를 이용한 비동기 지원
 - 통신 과정에서 순서보장이 필요하면, async*-yield를 이용한 stream(스트림)  

 

Posted by 목표를 가지고 달린다
,