본문 바로가기

Android

[Dagger2] Assisted Injection

Dagger 2.31 버전에 @Assisted, @AssistedInjection 등 Assisted Injection 관한 내용들이 추가되었다.

최신버전은 2.35.1 버전이다.

 

@AssistedInjection 이 언제 사용되는지를 알아보자.

기존 의존성 주입 예제들과는 다르게 주입되는 값이 상황에 따라 변하는 경우 Assisted Injection을 사용한다.

 

앱에서 사용자 정보를 보는 화면을 생각하면 된다.

사용자 별로 ID, Phone Number 등 다른 정보를 입력받아 ViewModel에 의존성 주입을 해줄 때 Assisted Injection을 사용할 수 있다.

 

우선 간단한 예제를 보자.

 

Robot 객체를 만들려 하는데 Robot의 이름은 입력받고, Robot의 Version은 항상 최신 버전(고정된 값)을 사용하기로 하자.

 

Robot 객체는 다음과 같이 만들어진다.

 

public class Robot {
    private String name;
    private int version;

    @AssistedInject
    public Robot(@Assisted String name, int version) {
        this.name = name;
        this.version = version;
    }

    public String getName() {
        return name;
    }

    public int getVersion() {
        return version;
    }

    @AssistedFactory
    public interface RobotFactory {
        Robot create(String name);
    }
}

 

Robot Constructor에 @AssistedInject 어노테이션이 붙었고, 입력받을 name에는 @Assisted 어노테이션이 붙었다.

 

그리고 아래쪽에 보면 @AssistedFactory 어노테이션이 붙은 RobotFactory를 만들어준다.

 

Module과 Component를 살펴보자.

 

@Module
public class RobotModule {
    @Provides
    int getInt() {
        return 123;
    }
}

 

Robot의 경우 version은 기존과 동일하게 의존성 주입을 받아야 하므로 위와같이 Module을 만들어준다.

 

@Component(modules = RobotModule.class)
public interface RobotComponent {
    Robot.RobotFactory getRobotFactory();
}

 

Component에서는 RobotFactory를 반환해준다.

 

이후 아래 코드와 같이 테스트하고 로그를 확인해보자.

 

private void testDagger() {
    String name = "Android";

    RobotComponent robotComponent = DaggerRobotComponent.create();
    Robot robot = robotComponent.getRobotFactory().create(name);

    Log.d(TAG, "name  : " + robot.getName());
    Log.d(TAG, "version : " + robot.getVersion());
}

 

D/test_dagger: name    : Android
D/test_dagger: version : 123

 

예상한대로 결과가 나오는 것을 확인할 수 있다.

 


ViewModel에 AssistedInjection 적용하기

이제 ViewModel에 AssistedInjection을 어떻게 사용할 수 있는지 예제를 통해 알아보자.

 

public class MainViewModel extends ViewModel {
    static final String CAFE = "cafe";
    static final String ARTICLE = "article";
    @NonNull private final Integer mCafeId;
    @NonNull private final Integer mArticleId;

    @AssistedInject
    public MainViewModel(@NonNull @Assisted(CAFE) Integer cafeId, @NonNull @Assisted(ARTICLE) Integer articleId) {
        mCafeId = cafeId;
        mArticleId = articleId;
    }

    public int getCafeId() {
        return mCafeId;
    }

    public int getArticleId() {
        return mArticleId;
    }

    @AssistedFactory
    public interface VMFactory {
        MainViewModel create(@Assisted(CAFE) int cafeId, @Assisted(ARTICLE) int articleId);
    }

    public static ViewModelProvider.Factory getFactory(VMFactory factory, int cafeId, int articleId) {
        return new ViewModelProvider.Factory() {
            @NonNull
            @Override
            public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
                return (T) factory.create(cafeId, articleId);
            }
        };
    }
}

 

Robot과 비교해보면 모든 변수가 Assisted되는 차이가 있다.

 

이럴 경우 Module을 만들지 않아도 된다.

 

그리고 Assisted되는 변수가 2개라서 각각을 식별자로 구분해줘야 한다.

(이 부분이 2.32에 추가되었다. 2.31에서 삽질함... 항상 버전 확인 하자)

 

Assisted 변수가 여러개일 경우, 식별자로 구분하지 않으면 순서가 뒤엉킬 수 있다.

 

@Component
public interface VMComponent {
    MainViewModel.VMFactory getVMFactory();
}

 

Component는 Robot의 Component와 동일한 구조다.

 

private void testViewModel() {
    int cafeId = 11111;
    int articleId = 55555;

    VMComponent vmComponent = DaggerVMComponent.create();

    MainViewModel mainViewModel = new ViewModelProvider(this, MainViewModel.getFactory(vmComponent.getVMFactory(), cafeId, articleId)).get(MainViewModel.class);

    Log.d(TAG, "cafeId    : " + mainViewModel.getCafeId());
    Log.d(TAG, "articleId : " + mainViewModel.getArticleId());
}

 

해당 코드로 테스트를 하고 로그를 확인해보자.

 

D/test_dagger: cafeId    : 11111
D/test_dagger: articleId : 55555

 

예상처럼 로그가 나오는 것을 확인할 수 있다.

 


Reference

'Android' 카테고리의 다른 글

[Dagger2] Multi Binding(3)  (0) 2021.05.03
[Dagger2] Multi Binding(2)  (0) 2021.05.03
[Dagger2] Multi Binding(1)  (0) 2021.05.02