AndroidAnnotations는 어떤 객체에 대한 주입(injection)이 완료된 이후에 코드를 실행할 수 있는 @AfterInject 어노테이션을 제공합니다. 

그리고  GuiceyFruitMycilaGuice 같은 라이브러리도 인젝션에 대한 콜백을 받을 수 있는 JSR250의 @PreDestroy, @PostConstruct 어노테이션을 구현하여 제공합니다.

그러나 대표적인 안드로이드용 Injection 프레임워크인 RoboGuice는 객체가 생성되고 필드에 대한 주입이 모두 끝난 이후 지정된 메소드(ex. 초기화 메소드)를 실행하는 깔끔한 방법을 제공하지 않습니다. 


다행히 방법이 전혀 없는 것은 아닙니다. 2가지 방법이 존재합니다.


1. InjectionListener를 이용

유연한 방법은 아니지만 Guice의 InjectionListener를 구현하여 주입이후에 지정된 메소드를 실행하게 할 수 있습니다.

(아래 코드에서는 MyInitClass 객체에 대한 모든 주입이 끝나고 나서 init 메소드를 실행합니다)


bindListener(Matchers.subclassesOf(MyInitClass.class), new TypeListener() {

    @Override

    public <I> void hear(final TypeLiteral<I> typeLiteral, TypeEncounter<I> typeEncounter) {

        typeEncounter.register(new InjectionListener<I>() {

            @Override

            public void afterInjection(Object i) {

                MyInitClass m = (MyInitClass) i;

                m.init();

            }

        });

    }

});



2. @Inject를 이용

Guice는 필드에 대한 모든 주입을 끝내고 나면 @Inject가 붙은 메소드를 실행한다고 합니다. 


    @Inject

    protected void init() {

       ... ...

    }


이 방법은 약간의 트릭에 해당하지만 매우 간단하기 때문에 저는 이 방법을 사용합니다. 자세한 내용은 다음 링크를 참고하세요.


http://stackoverflow.com/questions/2093344/guice-call-init-method-after-instantinating-an-object



신고
Posted by 에코지오

댓글을 달아 주세요

RoboGuice 사용시에 클래스 타입만으로는 주입받을 모듈을 구분하기 어려운 경우가 있습니다. 

예들들어 시간이 오래걸리는 작업을 처리하는 동안 사용자에게 진행중임을 알려주는 다이얼로그가 필요해서 아래처럼 Dialog를 주입받는 코드를 작성했습니다.


@Inject

protected Dialog progressDialog;


위 코드에서 우리가 원하는 것은 작업이 진행중임을 알려주는 Dialog를 주입시키는 것입니다. 그러나 다른 모듈에서는 다른 모양의 Dialog가 주입되어야 하는데 저 Dialog 타입만으로는 그것을 구분할 수 없습니다.


이런 상황에서는 추가적인 정보를 제공하는 어노테이션을 이용하면 됩니다. 위 예제의 경우 먼저 @TaskProgressDialog와 같은 어노테이션을 만들어 추가해줍니다.  


@Inject

@TaskProgressDialog

protected Dialog progressDialog;


그리고 Guice 모듈설정에서 AnnotatedBindingBuilder.annotatedWith() 메소드를 통해 해당 어노테이션이 붙은 놈에 적절한 모듈을 주입합니다.


protected void configure() {

  bind(Dialog.class).annotatedWith(TaskProgressDialog.class).toProvider(TaskProgrerssDialogProvider.class);

  ... ...

}


이렇게 하면 Dialog 타입이면서 @TaskProgressDialog 어노테이션이 붙어 있는 놈한테만 TaskProgressDialogProvider가 생성한 Dialog 객체가 주입될 것입니다.


* 참고로, Guice는 문자열을 통해 어노테이션을 구분할 수 있는 @Named 어노테이션을 제공합니다. 그러니까 필요시마다 TaskProgressDialog 같은 별도의 어노테이션 클래스를 만들 필요가 없다는 얘기입니다. 단, 문자열이 이용되므로 보조적인 수단으로만 사용을 권장합니다.


public class RealBillingService implements BillingService {

  @Inject

  public RealBillingService(@Named("Checkout") CreditCardProcessor processor,

      TransactionLog transactionLog) {

    ...

  }


Guice 모듈설정에서는 Names.named() 를 이용합니다.


bind(CreditCardProcessor.class).annotatedWith(Names.named("Checkout")).to(CheckoutCreditCardProcessor.class);






신고
Posted by 에코지오

댓글을 달아 주세요

추상(abstract) 애스펙트 클래스를 상속받아 포인트컷 메소드나 어드바이스 메소드를 오버라이딩하는 경우에 무엇이 적용되는가에 대해서 정리합니다. (참고로 애스펙트는 abstract 애스펙트만 상속받을 수 있습니다)


포인트컷 메소드 오버라이딩


추상 애스펙트에 정의된 (non-abstract) 포인트컷 메소드를 하위 애스펙트에서 오버라이딩하는 경우


(1) 포인트컷을 재정의하지 않은 경우

=> 추상 애스펙트의 포인트컷이 적용됨


(2) 포인트컷을 재정의한 경우 

=> 하위 애스펙트의 포인트컷이 적용됨


결론 : 자식 애스펙트에서 부모 애스펙트에 정의된 포인트컷을 재정의할 수 있다.



어드바이스 메소드 오버라이딩


추상 애스펙트에 정의된 어드바이스 메소드를 하위 애스펙트에서 오버라이딩하는 경우


(1) 어드바이스를 재정의하지 않은 경우

=> 추상 애스펙트의 어드바이스가 적용되지만 동작(메소드)는 하위 애스펙트의 것이 적용됨


(2) 어드바이스도 재정의한 경우

=> 추상 애스펙트의 어드바이스도 적용되고 하위 애스펙트의 어드바이스도 적용됨. 동작(메소드)은 하위 애스펙트의 것이 적용됨


결론 : 자식 애스펙트에서는 부모 애스펙트에 정의된 어드바이스의 동작(메소드 내용)은 재정의할 수 있지만,

언제(before, after 등) 어드바이스를 적용할지는 수정할 수 없다(무조건 새로운 적용 위치가 추가됨).


신고
Posted by 에코지오

댓글을 달아 주세요



티스토리 툴바