1. Flutter가 인기 있는 이유
하나의 코드 베이스로 여러 디바이스에서 애플리케이션을 개발할 수 있는 Flutter는 최근 몇 년 사이에 개발자 사이에서 엄청난 인기를 바탕으로 오늘날 가장 인기있는 크로스 플랫폼 프레임워크가 되었습니다.
Flutter가 인기 있는 이유 중 하나는 개발 속도 뿐만 아니라 애플리케이션의 속도 역시 굉장히 빠르다는 것입니다. 경쟁 프레임워크라고 할 수 있는 React Native(RN)보다 몇 배는 빠른 퍼포먼스를 보여주고 있기 때문에 성능과 사용자 경험을 중요하게 생각하는 기업일수록 Flutter를 도입하는 경우가 많아지고 있는 추세입니다.
최근 추세를 보면 Dart 언어와 Flutter 프레임워크의 점유율이 급속도로 빠르게 성장하고 있으며, 구글의 지원하에 앞으로 몇 년 동안 성장세를 유지할 것이라는 전망이 많습니다. 특히 Universal Studio나 eBay와 같은 글로벌 기업뿐만 아니라 Supercell과 같은 게임 개발 기업에서도 Flutter를 도입하면서 시장에서도 인정을 받는 추세입니다.
2. 플러터 성능의 비결
Flutter가 iOS의 Swift나 Android의 Kotlin과 같은 네이티브 코드들과 견주어도 비슷한 수준의 퍼포먼스를 내는 이유는 다양합니다. 먼저 Flutter는 ARM 아키텍쳐로 컴파일 되는 프로그래밍 언어인 Dart를 아용합니다. Dart는 Flutter를 개발하기 위해 구글에서 만든 프로그래밍 언어로, 얼마 전 업데이트를 통해 강력하고 빠른 성능을 자랑하면서 강력한 Null Safty를 지원해 프로그래머의 의도대로 애플리케이션을 만드는데 도움을 줍니다.
Flutter는 Skia라는 그래픽 엔진을 사용합니다. Skia는 오픈소스 2D 그래픽 라이브러리로, 구글은 Flutter 이전에도 크로미움(크롬) 브라우저와 ChromeOS 등에서 Skia를 도입한 적이 있습니다. Skia는 C++ 언어로 작성이 되어 있기 때문에 강력한 성능과 효율성을 보여줍니다.
또한 Flutter는 안정적으로 60fps의 성능을 보여주기 위해 독특한 프레임워크 구조를 가지고 있습니다. Flutter의 화면에서 보이는 보든 오브젝트인 Widget은 변경불가능(immutable)한 특성을 가지고 있습니다. 따라서 같은 화면이라도 위젯의 상태가 업데이트 되면, 그 위젯은 다시 빌드가 되어야 합니다. 이 과정에서 불필요한 빌드를 줄이기 위해 Flutter는 트리 구조를 참조하여 실제로 변경이 된 부분만 업데이트하는 과정을 거칩니다.
Flutter의 트리 구조는 Widget Tree, Object Tree 그리고 Render Tree라는 세 개의 트리로 이루어져있습니다. 오늘은 트리 구조 중 하나인 Widget Tree에 대해 알아보겠습니다.
3. Widget Tree
Flutter의 모든 UI 오브젝트는 Widget이라고 할 수 있습니다. 심지어 애플리케이션 역시 Widget이라고 할 수 있습니다. Flutter를 프로젝트를 처음 만들면 보이는 예시 코드에서 MyApp 클래스 역시 Widget입니다. 이는 Flutter의 소스코드를 보면 확인할 수 있습니다.
// project/main.dart
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget{
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
//flutter/lib/src/framework/statelessWidget.dart
abstract class StatelessWidget extends Widget {
const StatelessWidget({ super.key });
@override
StatelessElement createElement() => StatelessElement(this);
...
}
// flutter/lib/src/framework.dart
abstract class Widget extends DiagnosticableTree {
/// Initializes [key] for subclasses.
const Widget({ this.key });
final Key? key;
@protected
@factory
Element createElement();
...
}
StatelessWidget은 Widget 클래스의 상속이고, Widget 추상 클래스는 다시 DiadnosticableTree의 상속이라는 것을 확인할 수 있습니다. Widget Tree는 이런 Widget들의 계층을 트리의 자료구조로 나타내는 것이라고 할 수 있습니다. 즉, Widget들의 상호 관계(부모/자식)들을 관리하는 것은 각각의 Widget이 아니라 Widget Tree 구조가 담당합니다.
이러한 특성을 이해한다면 더 나은 프로그래밍을 할 수 있습니다. 예를 들어 여러 개의 child를 가지고 있는 자료구조에서 의도치 않게 원치 않는 Widget이 삭제되는 경우가 있습니다. 아래에서 어떤 Widget이 UI로 그려지고 조작될 때 원하지 않는 Widget이 삭제, 변경 될 수 있습니다.
// Some List of Widgets
class SomeWidget extends StatelessWidget{
...
return GestureDetector(
...
onTap: (){ deleteThisWidget(); }
);
}
List<Widget> _widgets = [
SomeWidget(text: '1'),
SomeWidget(text: '2'),
SomeWidget(text: '3'),
]
...
ListView.build(
...
build: (index, context) {
return _widgets[index];
}
)
이는 Widget의 계층 정보를 Widget 자체가 아니라 Widget Tree에서 관리하기 때문입니다. Widget을 조작하는 것으로는 트리에서 원하는 노드를 삭제하기 어렵기 때문입니다. 따라서 실수로 원치 않는 Widget을 제거하거나 변경하지 않기 위해서는 각 위젯에 Key를 부여하면 됩니다.
// Some List of Widgets with Keys
class SomeWidget extends StatelessWidget{
...
return GestureDetector(
...
onTap: (){ deleteThisWidget(); }
);
}
List<Widget> _widgets = [
SomeWidget(text: '1', key: '1'),
SomeWidget(text: '2', key: '2'),
SomeWidget(text: '3', key: '3'),
]
...
ListView.build(
...
build: (index, context) {
return _widgets[index];
}
)
위처럼 Widget Key를 부여하면 Widget Tree는 각 Widget의 고유한 값을 참조할 수 있기 때문에 원치 않는 조작을 방지할 수 있습니다. 이는 특히 ListView, GridView와 같은 클래스처럼 다이나믹한 자료구조를 나타내는 클래스를 사용할 때 중요합니다. 데이터베이스 등에서 데이터를 불러오는 경우에는 PK(Primary Key) 혹은 UID와 같은 정보를 Widget Key로 사용할 수 있습니다. 기회가 된다면 Flutter 프레임워크 내부 구조에서 사용되는 다양한 Key에 대해 다루어보겠습니다.
'Tech' 카테고리의 다른 글
[Flutter] Dart와 Flutter 업데이트 (1) | 2024.06.14 |
---|---|
[Flutter] 플러터의 트리 구조 (2/2) (0) | 2024.05.31 |
[Flutter] 웹뷰 패키지 2종 비교 (24) | 2024.05.10 |