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에 따라 라이센스가 부여됩니다.