
Flutter를 위한 초경량 고성능 상태 관리, 의존성 주입, 라우트 관리 솔루션
.obs와 Obx()만으로 간단한 반응형 UI 구현. setState() 불필요.
// Controller
var count = 0.obs;
void increment() => count++;
// UI
Obx(() => Text('${count}'))Context 없이 어디서든 화면 이동 가능. Navigator 불필요.
Get.to(NextScreen());
Get.back();
Get.offAll(HomePage()); // 모든 이전 화면 제거자동 메모리 관리. 화면이 닫히면 자동으로 컨트롤러 제거.
// 등록
Get.put(Controller());
// 사용
final c = Get.find<Controller>();BuildContext 없이 어디서든 호출 가능.
Get.snackbar('Title', 'Message');
Get.defaultDialog(title: 'Alert');상태관리 + 라우팅 + Dialog를 한 번에 처리.
class AuthController extends GetxController {
var isLoggedIn = false.obs;
void login() async {
var result = await loginAPI();
if (result) {
isLoggedIn(true);
Get.offAll(HomePage());
Get.snackbar('Success', 'Login OK');
}
}
}GetBuilder는 수동 update(), Obx는 자동 반응형. 용도에 맞게 선택.
// GetBuilder - 수동 업데이트
GetBuilder<CountController>(
builder: (controller) => Text('${controller.count}'),
)
controller.count++;
controller.update(); // 수동 호출 필요
// Obx - 자동 반응형
Obx(() => Text('${controller.count.value}'))
controller.count++; // 자동 업데이트컨트롤러를 필요할 때까지 생성하지 않음. 메모리 최적화.
// 즉시 생성
Get.put(HeavyController());
// 지연 로딩 - 처음 사용 시 생성
Get.lazyPut(() => HeavyController());
// 사용
final controller = Get.find<HeavyController>();
// 이 시점에 생성됨onClose()에서 리소스 정리. Stream, Timer 등 수동 취소 필수.
class MyController extends GetxController {
StreamSubscription? _subscription;
Timer? _timer;
@override
void onInit() {
super.onInit();
_subscription = stream.listen(...);
_timer = Timer.periodic(...);
}
@override
void onClose() {
_subscription?.cancel();
_timer?.cancel();
super.onClose();
}
}반응형 변수 변화에 자동으로 함수 실행.
class SearchController extends GetxController {
var searchText = ''.obs;
@override
void onInit() {
// 1초 debounce로 API 호출
debounce(searchText, (_) => searchAPI(),
time: Duration(seconds: 1));
// 값이 변경될 때마다 실행
ever(searchText, (_) => print('Changed'));
// 처음 한 번만 실행
once(searchText, (_) => print('First change'));
super.onInit();
}
}앱 전체에서 유지되는 서비스. Get.delete로도 제거 불가.
class SettingsService extends GetxService {
var isDarkMode = false.obs;
Future<SettingsService> init() async {
// 초기화 로직
return this;
}
}
// main.dart
await Get.putAsync(() => SettingsService().init());
// 어디서든 접근
final settings = Get.find<SettingsService>();페이지별 의존성을 라우트에 바인딩. 자동 정리.
class HomeBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => HomeController());
Get.lazyPut(() => ApiService());
}
}
// 라우트 정의
GetPage(
name: '/home',
page: () => HomePage(),
binding: HomeBinding(),
)인증, 권한 체크 등 라우트 접근 제어.
class AuthMiddleware extends GetMiddleware {
@override
RouteSettings? redirect(String? route) {
final authService = Get.find<AuthService>();
return authService.isLoggedIn
? null
: RouteSettings(name: '/login');
}
}
// 라우트에 적용
GetPage(
name: '/profile',
page: () => ProfilePage(),
middlewares: [AuthMiddleware()],
)다국어 지원. 키-값 기반 번역 시스템.
class Messages extends Translations {
@override
Map<String, Map<String, String>> get keys => {
'en_US': {
'hello': 'Hello',
'welcome': 'Welcome'
},
'ko_KR': {
'hello': '안녕하세요',
'welcome': '환영합니다'
},
};
}
// main.dart
GetMaterialApp(
translations: Messages(),
locale: Locale('ko', 'KR'),
)
// 사용
Text('hello'.tr) // "안녕하세요"다크모드 전환. 상태 유지 및 즉시 적용.
class ThemeController extends GetxController {
var isDark = false.obs;
void toggleTheme() {
isDark.value = !isDark.value;
Get.changeTheme(
isDark.value ? ThemeData.dark() : ThemeData.light()
);
}
}
// 사용
Obx(() => Switch(
value: controller.isDark.value,
onChanged: (_) => controller.toggleTheme(),
))상태관리, CRUD, 리스트 렌더링 통합 예제.
class TodoController extends GetxController {
var todos = <Todo>[].obs;
void addTodo(String title) {
todos.add(Todo(title: title));
}
void removeTodo(int index) {
todos.removeAt(index);
}
void toggleDone(int index) {
todos[index].isDone = !todos[index].isDone;
todos.refresh(); // 리스트 갱신
}
}
// UI
Obx(() => ListView.builder(
itemCount: controller.todos.length,
itemBuilder: (context, index) =>
CheckboxListTile(
value: controller.todos[index].isDone,
onChanged: (_) => controller.toggleDone(index),
),
))실시간 폼 검증 및 에러 메시지 표시.
class FormController extends GetxController {
var email = ''.obs;
var password = ''.obs;
String? get emailError =>
email.value.isEmpty ? 'Email required' :
!email.value.contains('@') ? 'Invalid email' : null;
String? get passwordError =>
password.value.length < 6 ? 'Min 6 characters' : null;
bool get isValid =>
emailError == null && passwordError == null;
}
// UI
Obx(() => TextField(
onChanged: (v) => controller.email.value = v,
decoration: InputDecoration(
errorText: controller.emailError,
),
))GetX 사용 시 메모리 누수와 성능 문제 방지 가이드.
// ✅ onClose()에서 리소스 정리
@override
void onClose() {
_subscription?.cancel();
super.onClose();
}
// ✅ 지연 로딩으로 메모리 절약
Get.lazyPut(() => Controller());
// ✅ Bindings로 자동 정리
GetPage(binding: HomeBinding())
// ✅ Workers는 onInit()에서 등록
debounce(variable, callback);
// ❌ onClose() 없이 Stream/Timer 방치 금지
// ❌ Get.put() 남용 금지 (필요할 때만)
// ❌ Obx 안에서 복잡한 로직 금지
// ❌ 전역 상태 과다 사용 금지