Dagger 2 학습 및 탐색(5)
@Inject
를 추가한 것은 구조기 주입에 속했고 방법 주입도 간단했다. 일반적으로 get 방법으로 필요한 것을 얻는다. 방법 주입이라고 해도 구성원 주입은 구성원 변수에 @Inject
기호를 추가하고 Dagger는 값을 부여함으로써 주입을 실현한다.바디 코드
그럼 이제 더 복잡한 교차 의존 관계를 탐색해 보자.현재
ClassB
:public class ClassB {
private ClassA classA;
private int a;
public ClassB(ClassA classA, int a) {
this.classA = classA;
this.a = a;
}
public ClassA getClassA() {
return classA;
}
public int getA() {
return a;
}
}
동시에 우리가 요구한
ClassA
의 첫 번째 변수도 a이다.이 가능하다, ~할 수 있다,...어쨌든 @Provides
방법을 추가해서 ModuleB
에 Dagger가 직접 찾도록 하자.@Module
public class ModuleB {
private int a;
private int b;
public ModuleB(int a, int b) {
this.a = a;
this.b = b;
}
@Provides
@Named("a")
int provideIntA() {
return a;
}
@Provides
@Named("b")
int provideIntB() {
return b;
}
@Provides
ClassA provideClassA(@Named("a") int a, @Named("b") int b) {
return new ClassA(a, b);
}
@Provides
ClassB provideClassB(ClassA classA, @Named("a") int a) {
return new ClassB(classA, a);
}
}
그리고
ClassBComponent
그대로 조롱박을 그린다.@Component(modules = ModuleB.class)
public interface ClassBComponent {
void inject(MainActivity mainActivity);
}
그리고 앞의
MainActivity
에 대한 ClassA
코드를 삭제합니다.public class MainActivity extends AppCompatActivity {
@Inject ClassB classB;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerClassBComponent.builder()
.moduleB(new ModuleB(2, 3))
.build().inject(this);
Log.d(TAG, classB.getClassA().getA() + ":" + classB.getClassA().getB() + ":" + classB.getA());
}
}
실행을 클릭하면 컴파일 오류가 발생할 때까지 모든 것이 완벽해 보입니다.
Error:(10, 8) : daggerplay.com.daggerplay.classes.ClassB cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
daggerplay.com.daggerplay.classes.ClassB is injected at
daggerplay.com.daggerplay.MainActivity.classB
daggerplay.com.daggerplay.MainActivity is injected at
daggerplay.com.daggerplay.components.ClassAComponent.inject(mainActivity)
이 잘못된 힌트를 보니 좀 헷갈리는 것 같다.
@Provides
이미 표시ClassB
했잖아.사실 뒤에 몇 줄이 포인트야.뒤의 몇 줄은 ClassAComponent
가 이미 주입MainActivity
을 맡았다는 것을 일깨워 준다.ClassAComponent
의 inject
함수를 삭제하였는데, 과연 프로그램이 정상적으로 작동하였다.그럼 도대체 어떻게 된 일입니까?인터넷에 검색해보니 이미 이런 의문이 있었다.https://stackoverflow.com/questions/32341839/multiple-independent-component-injection그리고 깃허브에서도 issue를 제기했다. 한마디로 상관없는 두 사람Component
은 같은 대상에 주입하는 것을 책임질 수 없다는 것이다.그럼 질문이 왔습니다. 만약에 우리가 주입ClassA
하고 싶고 주입ClassB
하고 싶으면 어떻게 합니까?답은 하나Component
에 넣는 것이다.문제는 하나Component
가 어떻게 여러 대상에 주입됩니까?곰곰이 생각해 보니 사실ClassA
의 제공 방법은 이미 ModuleB
안에 있다. Dagger에게 그것을 덧붙여ClassA
도 주입하도록 하는 방법이 없을까?네, 사실 간단해요. 예전처럼 MainActivity
에 ClassA
에 표시하면 돼요.지금은 이전의 ClassAComponent
와 ModuleA
를 삭제할 수 있다.현재MainActivity
는 다음과 같습니다.public class MainActivity extends AppCompatActivity {
@Inject ClassA classA;
@Inject ClassB classB;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ClassBComponent daggerClassBComponent = DaggerClassBComponent.builder()
.moduleB(new ModuleB(2, 3))
.build();
daggerClassBComponent.inject(this);
Log.d(TAG, classA.getClass().getSimpleName());
Log.d(TAG, classB.getClass().getSimpleName());
}
}
ModuleB
: @Component(modules = ModuleB.class)
public interface ClassBComponent {
void inject(MainActivity mainActivity);
}
운행하면 동시에 주입
ClassA
과ClassB
.만약 하나만 원한다면, 하나의 표시 클래스만 남기면 된다.이것 또한 Dagger를 사용할 때 가장 좋은 습관을 알려준다. 모든 의존을 한 Component
에 한 번에 주입하는 것이다.코드 생성
아니면 코드 생성을 관례대로 살펴봅시다.
rebuild
를 기억해라. 그렇지 않으면 원래ClassA
의 Dagger 생성 코드가 아직 존재한다.먼저 4개 공장류로 각각 정수 a, 정수 b,ClassA
와 ClassB
를 제공한다.이전 코드와 같은 방식이어서 붙이지 않겠습니다.그리고 새로운 주입기MainActivity_MembersInjector
:public final class MainActivity_MembersInjector implements MembersInjector {
private final Provider classAProvider;
private final Provider classBProvider;
public MainActivity_MembersInjector(
Provider classAProvider, Provider classBProvider) {
assert classAProvider != null;
this.classAProvider = classAProvider;
assert classBProvider != null;
this.classBProvider = classBProvider;
}
public static MembersInjector create(
Provider classAProvider, Provider classBProvider) {
return new MainActivity_MembersInjector(classAProvider, classBProvider);
}
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.classA = classAProvider.get();
instance.classB = classBProvider.get();
}
public static void injectClassA(MainActivity instance, Provider classAProvider) {
instance.classA = classAProvider.get();
}
public static void injectClassB(MainActivity instance, Provider classBProvider) {
instance.classB = classBProvider.get();
}
}
단독 주입
ClassA
과ClassB
도 가능하다는 것을 알 수 있다.하지만 우리는 보통 이런 종류를 직접 사용하지 않는다.다시 보기DaggerClassBComponent
:public final class DaggerClassBComponent implements ClassBComponent {
private Provider provideIntAProvider;
private Provider provideIntBProvider;
private Provider provideClassAProvider;
private Provider provideClassBProvider;
private MembersInjector mainActivityMembersInjector;
private DaggerClassBComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.provideIntAProvider = ModuleB_ProvideIntAFactory.create(builder.moduleB);
this.provideIntBProvider = ModuleB_ProvideIntBFactory.create(builder.moduleB);
this.provideClassAProvider =
ModuleB_ProvideClassAFactory.create(
builder.moduleB, provideIntAProvider, provideIntBProvider);
this.provideClassBProvider =
ModuleB_ProvideClassBFactory.create(
builder.moduleB, provideClassAProvider, provideIntAProvider);
this.mainActivityMembersInjector =
MainActivity_MembersInjector.create(provideClassAProvider, provideClassBProvider);
}
@Override
public void inject(MainActivity mainActivity) {
mainActivityMembersInjector.injectMembers(mainActivity);
}
public static final class Builder {
private ModuleB moduleB;
private Builder() {}
public ClassBComponent build() {
if (moduleB == null) {
throw new IllegalStateException(ModuleB.class.getCanonicalName() + " must be set");
}
return new DaggerClassBComponent(this);
}
public Builder moduleB(ModuleB moduleB) {
this.moduleB = Preconditions.checkNotNull(moduleB);
return this;
}
}
}
지금 문제가 하나 있다. 만약 우리가 하나의 단일 대상을 주입하기를 희망한다면 어떻게 실현할 것인가?어떻게 여러 번 초기화되는 것을 방지합니까?Dagger의
@Scope
표시를 언급하지 않을 수 없습니다. 다음에 다시 이 화제를 토론하겠습니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.