[Flutter GetX : 04] 종속성 관리, 의존성 주입(put, lazyPut, putAsync, create)

728x90

종속성 관리, 의존성 주입(put, lazyPut, putAsync, create)

 

목차
1. Get.put()
2. Get.lazyPut()
3. Get.putAsync()
4. Get.create()

 


provider 방식과 달리 getX는 context에 의존하지 않아서 Controller를 사용할 때만 선언하고 제거하기가 용이하다.

이러한 방식을 종속성 인스턴스 선언 방법이라고 하며, 총 4가지 방식이 제공된다.

 

  • Get.put()
  • Get.lazyPut()
  • Get.putAsync()
  • Get.create()

 

4가지 방식을 구현하기 위해 아래에 코드로 4개의 버튼을 구현하였다.

 

(main.dart)

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/home.dart';
import 'package:get/get.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      initialRoute: "/",
      getPages: [
        GetPage(name: "/", page: () => const Home()),
      ],
    );
  }
}

(src/home.dart)

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/pages/dependencys/dependency_manage.dart';
import 'package:flutter_getx/src/pages/reactive_state_manage_page.dart';
import 'package:get/get.dart';

class Home extends StatelessWidget {
  const Home({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("라우트 관리 홈"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: () {
                  Get.to(const DependencyManagePage());
                },
                child: const Text("의존성 관리"),
            ),
          ]
        )
      )
    );
  }
}

(src/pages/dependencys/dependency_manage.dart)

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/pages/dependencys/get_put.dart';

class DependencyManagePage extends StatelessWidget{
  const DependencyManagePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("의존성 주입"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: () {}
                child: const Text("Getput") 
            ),
            ElevatedButton(
                onPressed: () {},
                child: const Text("")
            ),
            ElevatedButton(
                onPressed: () {},
                child: const Text("")
            ),
            ElevatedButton(
                onPressed: () {},
                child: const Text("")
            ),
          ]
        )
      )
    );
  }
}

1. Get.put()

Get.put()은 곧바로 메모리에 컨트롤러의 인스턴스를 올리는 방식이다.

 

"Getput" 버튼을 누르면 컨트롤러가 생성될 수 있도록 구현하기 위해 다음과 같이 코드를 구현했다.

(src/controller/dependency_controller.dart)

import 'package:get/get.dart';

class DependencyController extends GetxController {

}

(src/pages/dependencys/get_put.dart)

import 'package:flutter/material.dart';

class GetPut extends StatelessWidget {
  const GetPut({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
    );
  }
}

그리고 아까 만든 dependency_manage.dart의 첫번째 버튼("Getput") 부분을 아래와 같이 바꾼다.

ElevatedButton(
                onPressed: () {
                  Get.to(
                      () => const GetPut(), // 이동할 페이지 명시
                    binding: BindingsBuilder((){ // 필요한 의존성들을 어떤 식으로 주입할 것인지 정의를 내리는 부분.
                      Get.put(DependencyController()); // 바인딩 : 페이지를 보내주면서(페이지 라우트 단계에서) 사용할 controller를 주입하는 방법// 지난번에는 넘어간 페이지에서 Get.put을 했었다.
                    }),
                  );
                },
                child: const Text("Getput"),
            ),

지난번에는 컨트롤러를 사용할 페이지에서 Get.put을 선언했었지만, binding을 사용하면 페이지를 보내주는 쪽에서도 인스턴스를 선언해줄 수 있다.

 

바인딩은 페이지 라우트 단계(페이지를 보내는 부분)에서 해당 페이지에서 사용하게 될 컨트롤러를 주입하는 방법이다.

결국, 버튼을 누르면 새로운 페이지와 함께 BindingBuilder를 통해 새로운 컨트롤러를 주입하게 된다.

 

참고로 Get.to(const GetPut(), ... 이렇게 해도 상관없으나 다음과 같은 경고 문구가 나타나는 것을 확인할 수 있다.

가급적이면 Get.to(() => Page()) 형태로 작성하는 것이 자동으로 메모리 관리를 해주는 GetX의 장점을 극한으로 이용할 수 있을 것으로 보인다.

Getput 버튼을 누르면 아까 만든 컨트롤러의 인스턴스가 자동으로 생성된다.
Getput 위젯에 딱히 뭘 한게 없기 때문에 빈 페이지가 나왔다. 여기서 뒤로가는 버튼을 누르면 생성되었던 컨트롤러 인스턴스가 자동으로 삭제되는 것을 확인할 수 있다.

클래스를 인스턴스화 한다는 것은 곧 메모리에 인스턴스를 올리는 것이기 때문에 과다하게 사용하면 성능이 느려지게 된다.

GetX는 위와같이 인스턴스를 더이상 사용하지 않게 될 때 알아서 인스턴스를 삭제해주는 방식으로 메모리 관리를 도와준다.

 

참고 : 만약 지 마음대로 인스턴스를 제거하는 것이 싫다면 permanent: true 값을 설정하면 된다.

 

2. Get.lazyPut()

put과 달리, 곧바로 인스턴스를 메모리에 올리는 것이 아니라, 컨트롤러에 실제로 접근할 때 올리는 방식이다.

ElevatedButton(
    onPressed: () {
        Get.to(
            () => const GetLazyPut(),
            binding: BindingsBuilder(() {
                Get.lazyPut<DependencyController>(() =>
                    DependencyController()
                ); 
                }
            ),
         );
     },
     child: const Text("Get.lazyPut")
),

lazyPut은 builder를 사용하기 때문에 <>에 타입을 명시하고 (() => ...()) 형태로 작성해야 한다.

실행시켜보면 Get.lazyPut 버튼을 누르고 뒤로가기를 눌러도 인스턴스가 생성되거나 삭제되지 않는다는 것을 확인할 수 있다.

lazyPut은 컨트롤러에 실제로 접근하는 때 인스턴스를 생성하기 때문이다.

 

dependency_controller.dart에 대충 아무 메서드나 넣어보자.

import 'package:get/get.dart';

class DependencyController extends GetxController {
  void increase() {}
}

그리고 src/pages/dependencys/get_lazyput.dart에 다음 코드를 작성한다.

버튼을 누르면 find()를 통해 컨트롤러에서 만든 increase 메서드를 실행시키는 것이다.

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/controller/dependency_controller.dart';
import 'package:get/get.dart';

class GetLazyPut extends StatelessWidget {
  const GetLazyPut({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: ElevatedButton(
        onPressed: () => {
          Get.find<DependencyController>().increase()
        },
        child: const Text("increase"),
      )
    );
  }
}

버튼을 누르면 컨트롤러 인스턴스가 생성된다.
그리고 뒤로가기를 누르면 메모리에서 인스턴스가 삭제되는 것을 확인할 수 있다!

 

3. Get.putAsync

ElevatedButton(
              onPressed: () {
                Get.to(
                      () => const GetPut(),
                  binding: BindingsBuilder(() {
                    Get.putAsync<DependencyController>(() async {
                      return DependencyController()
                    });
                  }),
                );
              },
              child: const Text("Get.putAsync")
          ),

put과 별 차이는 없어보이지만 비동기적으로 처리한다.

await를 넣어서 5초간 기다리도록 코드를 살짝 수정해보자.

 

ElevatedButton(
              onPressed: () {
                Get.to(
                      () => const GetPut(),
                  binding: BindingsBuilder(() {
                    Get.putAsync<DependencyController>(() async {
                      await Future.delayed(const Duration(seconds: 5));
                      return DependencyController();
                    });
                  }),
                );
              },
              child: const Text("Get.putAsync")
          ),

이제 Get.putAsync 버튼을 누르면 5초를 기다린 후, 인스턴스가 생성되는 것을 확인할 수 있다. 뒤로가기를 누르면 자동으로 메모리에서 인스턴스가 제거된다.

서버와의 통신이 필요할 때 사용할 수 있는 방법이다.

 

4. Get.create

위의 세가지 방식은 싱글톤 방식이기 때문에 인스턴스가 하나만 존재한다.

그러나 create는 인스턴스가 여러개 만들어질 수 있다는 차이점이 있다.

 

lazyPut과 같이, 컨트롤러에 실제로 접근할 때에만 인스턴스가 생성되는 것은 동일하나, 싱글톤 방식이 아니기 때문에 다른 객체가 계속해서 만들어질 수 있다.

ElevatedButton(
      onPressed: () {
        Get.to(
          () => const GetPut(),
          binding: BindingsBuilder(() {
            Get.create<DependencyController>(
                () => DependencyController());
          }),
        );
      },
      child: const Text("create")
),

 

get_put.dart를 다음과 같이 작성해보자.

버튼을 누르면 해당 컨트롤러의 인스턴스가 가지는 고유 번호를 터미널에 출력하도록 할 것이다.

import 'package:flutter/material.dart';
import 'package:get/get.dart';

import '../../controller/dependency_controller.dart';

class GetPut extends StatelessWidget {
  const GetPut({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
        body: ElevatedButton(
          onPressed: () => {
            print(Get.find<DependencyController>().hashCode),
            Get.find<DependencyController>().increase()
          },
          child: const Text("increase"),
        )
    );
  }
}

버튼을 누르면 인스턴스가 생성되긴 하나, 해시코드가 완전히 다른 새로운 객체로 생성되는 것을 확인할 수 있다.

4번째 케이스의 경우 웬만하면 사용하게 될 일은 없을 것 같다.

728x90