티스토리 뷰

반응형

이제 Flutter 입문서 마지막 책이다. 지금까지 본 책중에서 내용이 가장 알차다. 그렇다고 물론 초보가 이 책 한권을 본다면 다른 책을 안봐도 되는 것은 아닌 것 같다. 최소한 Do It 정도는 더보는 것을 추천한다. 이 두권을 보더라도 실제 앱을 짤 때에는 궁금하거나 모르는 부분이 무수히 나올텐데 이때부턴 구글링이 최고다. 

 

 

몰랐던 부분, 기억하고 싶은 내용

다트 네이티브 플랫폼은 JIT(Just In Time) 컴파일 방식과 AOT(Ahead of TIme)컴파일 방식을 이용한다. JIT 컴파일 방식은 다트 가상 머신에서 제공하는 기능으로 코드의 변경된 사항을 처음부터 다시 컴파일 할 필요 없이 즉시 화면에 반영할 수 있는 핫 리로딩 기능, 실시간으로 메트릭스를 확인할 수 있는 기능 디버깅 기능을 제공한다. 개발하는 도중에느 하드웨어 리소스를 적게 사용하는 것보다 빠르게 개발할 수 있는 효율이 중요하기 때문에 JIT 컴파일 방식을 사용하지만 소프트웨어를 배포할 때는 컴파일이 돼 있어야 더욱 리소스를 효율적으로 사요할 수 있다. 그래서 배포시에는 AOT 컴파일 방식을 사용해서 컴파일 한다. 

 

컬렉션(Set, List, Map)은 여러 값을 하나의 변수에 저장할 수 있는 타입이다. 컬렉션 타입은 서로의 타입으로 자유롭게 형변환이 가능하다는 매우 큰 장점이 있다. 

 

typedef 키워드는 함수의 시그니처를 정의하는 값으로 보면된다. 여기서 시그니처는 반환값 타입, 매개변수 개수와 타입등을 말한다. 즉 함수 선언부를 정의하는 키워드다. 아래와 같이 함수가 무슨 동작을 하는지에 대한 정의는 없다.  그럼 이 함수를 어떻게 사용할까? 시그니처에 맞춘 함수를 만들어서 사용하면된다. 

typedef Operation = void Function(int x, int y)

void add(int x, int y){
	print('결괏값: ${x+y}')
}

void main(){
	Operation oper = add;
    oper(1,2);
}

다트에서 함수는 일급 객체(First-class citizen)이므로 함수를 값처럼 사용할 수 있다. 

 

익명함수와 람다함수 모두 함수 이름이 없으며 일회성으로 쓸 때 사용한다. 

 

함수는 메서드를 포함하는 더 큰 개념이다. 클래스에 정의된 함수인 메서드는 클래스의 기능을 정의한 함수 이다. 

 

제네릭은 클래스나 함수의 정의를 선언할 때가 아니라 인스턴스화하거나 실행할 때로 미룬다. 특정 변수의 타입을 하나의 타입으로 제한하고 싶지 않을 때 자주 사용한다.

흔히 사용되는 제네릭 문자들 

T: 변수 타입(Type)을 표현할 때 흔히 사용

E: 리스트 내부 요소(Element)들의 타입을 표현할때 흔히 사용

K: 키(Key)를 표현할 때 흔히 사용  (ex Map<K, V>)

V: 값(value)을 표현할때 흔히 사용 

class Cache<T>{
	final T data;
    Cache({required this.data});
}

void main(){
	final cache = Cache<List<int>>(data: [1,2,3]);
    print(cache.data.reduce((value, element) => value+element));
}

 

SystemChrome 클래스는 시스템 UI의 그래픽 설정을 변경하는 기능을 제공한다. SystemChrome.setSystemUIOverlayStyle()을 사용하면 상태바의 색상을 변경할 수 있다. 매개변수의 값으로는 검정색으로 만들어주는 SystemUiOverlayStyle.dark 와 흰색으로 만들어주는 SystemUiOverlayStyle.light 가 있다. 

setEnabledSystemUIMode() : 앱의 풀스크린 모드를 지정

setPreferredOrientations(): 앱을 실행하는 방향을 지정

setSystemUiChangeCallback(): 시스템 UI가 변경되면 실행되는 콜백함수를 입력 할 수 있는 메서드

setSystemUIOverlayStyle(): 시스템 UI색상을 변경

 

Column 이나 Row 의 crossAxisAlignment 매개변수에 CrossAxisAlignment.Stretch 를 입력하면 children  위젯들의 box size에서 반대축을 최대 크기로 늘린다.  

 

.of(context) 로 정의된 모든 생성자는 일반적으로 BuildContext 를 매개변수로 받고 위젯 트리에서 가장 가까이에 있는 객체의 값을 찾아낸다. 결과적으로 MediaQuery.of(context)는 현재 위젯 트리에서 가장 가까이에 있는 MediaQuery 값을 찾ㅇ낸다. 앱이 실행되면 MaterialApp 이 빌드됨과 동시에 MediaQuery가 생성된다.

 

videoController!.value 에 는 status 정보들이 있다. 예를 들어 지금 재생중인지 알고 싶으면 videoController!.value.isPlaying 으로 알아 볼 수 있다. 현재 재생 위치를 알고 싶으면 videoController!.value.position 을 해보면된다. 

 

동영상 플레이어에서 새로운 영상을 재생시키려면, state class 에 videoController 변수가 있겠지만 바로 값을 입력하지 않고 initalizeController() 메서드를 만들어서 그안에서 새로 생성한 videoController 를 정의하고 videoController.initialize() 한뒤에 setState()를 이용해 state class의 videoController 에 넣어주면된다. 

 

FutuerBuilder를 사용할때, snapshot.connectionState 를 실행하면 비동기함수의 현재 실행 상태를 가져올 수 있다. 일반적으로 코드에서 사용하는 방식인 !snapshot.hasData 대신에 snapshot.ConnectionState == ConnectionState.waiting 을 사용해도 될 것 같지만 그렇게 코드를 작성하지 않는다. 이유는 캐싱(caching)때문이다. 캐싱은 데이터를 일시적으로 저장하고 기억하는것을 의미한다. FutureBuilder는 제공된 비동기 함수의 상태가 변경될 때마다 상위 build() 함수가 재실행된다. 그런데 FutureBuilder는 다른 위젯과 마찬가지로 build()함수에 영향을 받는다. build()가 다시 실행되면 FutureBuilder는 다시 렌더링되고 Builder()함수도 다시 실행된다. 그리고 그럴때마다 비동기 함수도 매번 다시 실행된다. 이때 매번 로딩 상태가 false로 돌아갔다가 함수가 끝날 때 다시 true 로 변하면 build() 함수가 실행될 때마다 CircularProgressIndicator 가 렌더링되어 화면에 깜박임이 생기게 된다.  build() 함수에 기존 반환받았던 데이터값을 기억해두면 이 상황을 막을 수 있다. 그러면 같은 build() 함수가 두번 이상 실행될때는 snapshot.connectionState 가 ConnectionState.waiting 이더라도 snapshot.data에서 기존 실행했던 함수의 반환값을 받아 볼 수 있다. 즉 화면 깜박거림 현상을 막을 수 있다. 그래서 snapshot.connectionState 대신에 snapshot.hasData를 사용해서 로딩 상태를 인지한다.

FutureBuilder(
	Future: init(),
    builder: (BuildContex context, AysncSnapshot snapshot){
    	if(!snapshot.hasData){
        	return Center(child: CircularProgressIndicator());
        }
        return Center(child: Text('완료'));
    }
)

 

Stack 위젯의 fit 매개변수에는 StackFit 을 입력할 수 있다. StackFit은 StackFit.loose와 StackFit.expand가 있다. loose는 자식들이 최소한의 크기만 차지하도록 하고 expand는 자식들이 차지할 수 있는 공간의 최대한의 크기르 차지하도록 한다. 

 

ImagePicker 플러그인은 네이티브 코드를 사용하는 플러그인이니 꼭 앱을 종료했다가 다시 시작해서 새로 구현한 함수를 테스트해야한다. 

 

StatefulWidget을 사용할 때 같은 (stateful)위젯 여러개를 리스트로 제공하려면 각각 위젯을 구분하는 key  매개변수를 지정해줘야 한다. 이값이 같으면 같은 위젯으로 인식하고 다르면 다른 위젯으로 인식한다. 

 

 화면의 특정 UI를 이미지로 변환하려면 RepaintBoundary 위젯을 이용해서 만들 수 있다. (14장에서 기존 이미지에 내가 원하는 스티커를 붙여서 다시 이미지로 저장하는 앱을 만들때 나옴)

 

화면을 아래로 당겼을때 refresh 되는 기능을 넣고 싶으면 RefreshIndicator 위젯을 사용하면 된다. Stateful 위젯의 build 함수에 FutureBuilder 를 사용하면 FutureBuilder 가 화면에 렌더링 될대마다 future 매개변수에 입력된 함수가 실행된다.

Widget build(BuildContext context){
	return Scaffold(
    	...생략....
        body: FutureBuilder<List<VideoModel>>(
        	Future: YoutubeRepository.getVideos(),
            builder: (context, snapshot){
            	...생략...
                return RefreshIndicator(
                	onRefresh: ()async{
                    	setState((){});
                    }
                    child: ListView(...생략...),
                );
            }
        )
    );
}

  

InstrinsicHeight 위젯은 내부 위젯들의 높이를 최대 높이로 맞춰준다. 내부 위젯중 최대 크기를 차지하는 위젯만큼 다른 위젯들 크기를 동일하게 맞춰준다. 

IntrinsicHeight(
	child: Row(
    	CrossAxisAlignment: CrossAxisAlignment.strech, 
        children:[...생략...]
    )
)

위와같은 예문이 있는데, Row 에서 이미 crossAxisAlignment로 최대 높이로 만들어줬는데 intrinsicHeight 가 또 필요한가? 

 

실제 기기에서는 텍스트필드를 누르면 키보드가 화면에 올라오는 만큼 텍스트 필드들이 가려진다. 잘 구현된 화면에서는 텍스트 필드가 아래에서 위로 올라온만큼 BottomSheet 위젯의 아래에 패딩을 추가해서 텍스트 필드 및 버튼이 가리지 않고 보이도록 한다. MediaQuery 클래스를 사용해서 키보드가 아래에 차지하는 크기를 가져온 다음 해당되는 크기만큼 패딩을 추가해서 키보드가 올라와도 모든 위젯들이 보이도록 코딩해야한다.

final bottomInset = MediaQuery.of(context).viewInsets.bottom; // 키보드 높이 가져오기

 

get_it 패키지는 Dependency Injection 즉 의존성 주입을 구현하는 플러그인이다. database 클래스를 프로젝트 전역에서 사용할 수 있어야 하는데 서브 위젯으로 값을 계속 넘겨주기에는 반복적인 코드를 너무 많이 사용해야한다. GetIt 으로 값을 한번 등록해두면 어디서든 처음에 주입한 값, 즉 같은 database 변수를 GetIt.I를 통해서 프로젝트 어디서든 사용할 수 있다. 

 

캐싱은 데이터를 기억한다는 뜻이다. 예를 들어 현재 구현한 ScheduleProvider 에서 cache 라는 변수가 존재하며 이변수에는 GET 메서드로 불러온 모든 일정 정보가 전부 담겨 있다. 그렇기 때문에 특정 날짜를 처음 선택했을 때는 데이터를 불러오는 시간이 걸리지만 같은 날짜를 다시 요청할 때는 기존 요청에서 기억하는 데이터를 지연 없이 불러올 수 있다. 그래서 UI에는 우선  cache 저장되어있던 일정을 보여주고,  GET 메스드로 해당 날짜의 데이터를 요청한다. 그리고 받아온 데이터가 현제 caching 데이터와 차이가 없다면 그대로 종료되고, 새로운 내용이 있다면 UI를 다시 업데이트해주고, cache도 업데이트 해주면 된다.

 

Rest API 를 연동할 때 캐싱 시스템을 구현하면 사용자에게 조금 더 빠르게 데이터를 보여줄 수 있다.

GET 메서드 캐싱의 기본은 요청으로 가져온 데이터를 저장해두었다가 재사용하는 방식이다. 

POST, DELETE 메서드 캐싱의 기본은 응답으로 받게 될 데이터를 예측하고 미리 캐시에 값을 반영하는 긍적적 응답 방식이다.

 

 파이어스토어를 이용해서 앱을 만들때 파이어스토어로부터 Stream을 사용하여 데이터를 가져온다면 문서(파이어스토어 저장되는 데이터 단위)가 변경될때마다 새로 데이터를 받아오기 때문에 과도한 데이터를 사용할 수 있다. streamBuilder 대신 FutureBuilder 를 사용해서 데이터 사용해서 데이터 사용량을 줄일 수 있다. 

 

 

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함