program story

Android 프로젝트에서 처음부터 DAGGER 종속성 주입을 설정하는 방법은 무엇입니까?

inputbox 2020. 8. 25. 07:58
반응형

Android 프로젝트에서 처음부터 DAGGER 종속성 주입을 설정하는 방법은 무엇입니까?


Dagger를 사용하는 방법? Android 프로젝트에서 작동하도록 Dagger를 구성하는 방법은 무엇입니까?

Android 프로젝트에서 Dagger를 사용하고 싶지만 혼란 스럽습니다.

편집 : Dagger2는 2015 년 04 월 15 일 이후로 출시되었으며 훨씬 더 혼란 스럽습니다!

[이 질문은 내가 Dagger1에 대해 더 많이 배우고 Dagger2에 대해 더 많이 배우면서 내 대답에 추가하는 "스텁"입니다. 이 질문은 "질문"이라기보다는 가이드에 가깝습니다.]


Dagger 2.x 가이드 (개정판 6) :

단계는 다음과 같습니다.

1) 추가 Dagger귀하에 build.gradle파일 :

  • 최상위 build.gradle :

.

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.0'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' //added apt for source code generation
    }
}

allprojects {
    repositories {
        jcenter()
    }
}
  • 앱 수준 build.gradle :

.

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt' //needed for source code generation

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.2"

    defaultConfig {
        applicationId "your.app.id"
        minSdkVersion 14
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    apt 'com.google.dagger:dagger-compiler:2.7' //needed for source code generation
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:24.2.1'
    compile 'com.google.dagger:dagger:2.7' //dagger itself
    provided 'org.glassfish:javax.annotation:10.0-b28' //needed to resolve compilation errors, thanks to tutplus.org for finding the dependency
}

2.)AppContextModule 종속성을 제공하는 클래스를 만듭니다 .

@Module //a module could also include other modules
public class AppContextModule {
    private final CustomApplication application;

    public AppContextModule(CustomApplication application) {
        this.application = application;
    }

    @Provides
    public CustomApplication application() {
        return this.application;
    }

    @Provides 
    public Context applicationContext() {
        return this.application;
    }

    @Provides
    public LocationManager locationService(Context context) {
        return (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
    }
}

3.)AppContextComponent 주입 가능한 클래스를 얻기 위해 인터페이스를 제공 하는 클래스를 만듭니다 .

public interface AppContextComponent {
    CustomApplication application(); //provision method
    Context applicationContext(); //provision method
    LocationManager locationManager(); //provision method
}

3.1.) 다음은 구현으로 모듈을 만드는 방법입니다.

@Module //this is to show that you can include modules to one another
public class AnotherModule {
    @Provides
    @Singleton
    public AnotherClass anotherClass() {
        return new AnotherClassImpl();
    }
}

@Module(includes=AnotherModule.class) //this is to show that you can include modules to one another
public class OtherModule {
    @Provides
    @Singleton
    public OtherClass otherClass(AnotherClass anotherClass) {
        return new OtherClassImpl(anotherClass);
    }
}

public interface AnotherComponent {
    AnotherClass anotherClass();
}

public interface OtherComponent extends AnotherComponent {
    OtherClass otherClass();
}

@Component(modules={OtherModule.class})
@Singleton
public interface ApplicationComponent extends OtherComponent {
    void inject(MainActivity mainActivity);
}

주의 : : 생성 된 구성 요소 내에서 범위가 지정된 공급자를 가져 오려면 모듈의 주석 처리 된 메서드 @Scope주석 ( @Singleton또는 @ActivityScope) 을 제공해야합니다 @Provides. 그렇지 않으면 범위가 지정되지 않으며 삽입 할 때마다 새 인스턴스를 받게됩니다.

3.2.) 주입 할 수있는 항목을 지정하는 응용 프로그램 범위 구성 요소를 만듭니다 ( injects={MainActivity.class}Dagger 1.x 의 경우와 동일 ).

@Singleton
@Component(module={AppContextModule.class}) //this is where you would add additional modules, and a dependency if you want to subscope
public interface ApplicationComponent extends AppContextComponent { //extend to have the provision methods
    void inject(MainActivity mainActivity);
}

3.3.) 생성자를 통해 직접 생성 있고를 사용하여 재정의하고 싶지 않은 종속성의 경우 @Module(예 : 구현 유형을 변경하기 위해 빌드 플레이버를 사용하는 경우) @Inject주석이있는 생성자를 사용할 수 있습니다 .

public class Something {
    OtherThing otherThing;

    @Inject
    public Something(OtherThing otherThing) {
        this.otherThing = otherThing;
    }
}

또한 @Inject생성자 를 사용 하면 명시 적으로 호출하지 않고도 필드 주입을 사용할 수 있습니다 component.inject(this).

public class Something {
    @Inject
    OtherThing otherThing;

    @Inject
    public Something() {
    }
}

이러한 @Inject생성자 클래스는 모듈에서 명시 적으로 지정할 필요없이 동일한 범위의 구성 요소에 자동으로 추가됩니다.

@Singleton범위 @Inject생성자 클래스에서 볼 수됩니다 @Singleton범위의 구성 요소.

@Singleton // scoping
public class Something {
    OtherThing otherThing;

    @Inject
    public Something(OtherThing otherThing) {
        this.otherThing = otherThing;
    }
}

3.4.) 주어진 인터페이스에 대한 특정 구현을 정의한 후 다음과 같이하십시오.

public interface Something {
    void doSomething();
}

@Singleton
public class SomethingImpl {
    @Inject
    AnotherThing anotherThing;

    @Inject
    public SomethingImpl() {
    }
}

.NET Framework를 사용하여 인터페이스에 특정 구현을 "바인딩"해야합니다 @Module.

@Module
public class SomethingModule {
    @Provides
    Something something(SomethingImpl something) {
        return something;
    }
}

Dagger 2.4 이후의 약어는 다음과 같습니다.

@Module
public abstract class SomethingModule {
    @Binds
    abstract Something something(SomethingImpl something);
}

4.)Injector 애플리케이션 수준 구성 요소를 처리 할 클래스를 만듭니다 (모 놀리 식을 대체 함 ObjectGraph).

(참고 : APT Rebuild Project를 사용하여 DaggerApplicationComponent빌더 클래스 생성 )

public enum Injector {
    INSTANCE;

    ApplicationComponent applicationComponent;

    private Injector(){
    }

    static void initialize(CustomApplication customApplication) {
        ApplicationComponent applicationComponent = DaggerApplicationComponent.builder()
           .appContextModule(new AppContextModule(customApplication))
           .build();
        INSTANCE.applicationComponent = applicationComponent;
    }

    public static ApplicationComponent get() {
        return INSTANCE.applicationComponent;
    }
}

5.)CustomApplication 수업 만들기

public class CustomApplication
        extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Injector.initialize(this);
    }
}

6) 추가 CustomApplication귀하에 AndroidManifest.xml.

<application
    android:name=".CustomApplication"
    ...

7.) 수업을MainActivity

public class MainActivity
        extends AppCompatActivity {
    @Inject
    CustomApplication customApplication;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Injector.get().inject(this);
        //customApplication is injected from component
    }
}

8.) 즐기십시오!

+1.) 활동 수준 범위 구성 요소를Scope 만들 수있는 구성 요소를 지정할 수 있습니다 . 하위 범위를 사용하면 전체 응용 프로그램이 아닌 지정된 하위 범위에 대해서만 필요한 종속성을 제공 할 수 있습니다. 일반적으로 각 활동은이 설정으로 자체 모듈을 가져옵니다. 범위가 지정된 공급자 는 구성 요소별로 존재합니다 . 즉, 해당 활동에 대한 인스턴스를 유지하려면 구성 요소 자체가 구성 변경을 유지해야합니다. 예를 들어, 또는 모르타르 범위를 통해 생존 할 수 있습니다.onRetainCustomNonConfigurationInstance()

하위 범위 지정에 대한 자세한 내용 은 Google 가이드를 확인하세요 . 또한 제공 방법구성 요소 종속성 섹션 에 대한이 사이트여기를 참조하십시오 .

사용자 지정 범위를 만들려면 범위 한정자 주석을 지정해야합니다.

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface YourCustomScope {
}

하위 범위를 만들려면 구성 요소에 범위를 지정 ApplicationComponent하고 종속성으로 지정해야 합니다. 분명히 모듈 공급자 메서드에도 하위 범위를 지정해야합니다.

@YourCustomScope
@Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
public interface YourCustomScopedComponent
        extends ApplicationComponent {
    CustomScopeClass customScopeClass();

    void inject(YourScopedClass scopedClass);
}

@Module
public class CustomScopeModule {
    @Provides
    @YourCustomScope
    public CustomScopeClass customScopeClass() {
        return new CustomScopeClassImpl();
    }
}

하나의 범위 구성 요소 종속성으로 지정할 수 있습니다. Java에서 다중 상속이 지원되지 않는 것과 똑같이 생각하십시오.

+2.) 정보 @Subcomponent: 본질적으로 범위 @Subcomponent는 구성 요소 종속성을 대체 할 수 있습니다. 그러나 주석 프로세서가 제공하는 빌더를 사용하는 대신 컴포넌트 팩토리 메소드를 사용해야합니다.

그래서 이거:

@Singleton
@Component
public interface ApplicationComponent {
}

@YourCustomScope
@Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
public interface YourCustomScopedComponent
        extends ApplicationComponent {
    CustomScopeClass customScopeClass();

    void inject(YourScopedClass scopedClass);
}

이렇게됩니다 :

@Singleton
@Component
public interface ApplicationComponent {
    YourCustomScopedComponent newYourCustomScopedComponent(CustomScopeModule customScopeModule);
}

@Subcomponent(modules={CustomScopeModule.class})
@YourCustomScope
public interface YourCustomScopedComponent {
    CustomScopeClass customScopeClass();
}

이:

DaggerYourCustomScopedComponent.builder()
      .applicationComponent(Injector.get())
      .customScopeModule(new CustomScopeModule())
      .build();

이렇게됩니다 :

Injector.INSTANCE.newYourCustomScopedComponent(new CustomScopeModule());

+3.) : Dagger2에 관한 다른 Stack Overflow 질문도 확인하세요. 많은 정보를 제공합니다. 예를 들어, 현재 Dagger2 구조 가이 답변에 지정되어 있습니다.

감사

Github , TutsPlus , Joe Steele , Froger MCSGoogle 의 가이드에 감사드립니다 .

또한 이 게시물을 작성한 후이 단계별 마이그레이션 가이드를 찾았습니다.

그리고 Kirill의 범위 설명위해 .

공식 문서 에 더 많은 정보가 있습니다 .


Dagger 1.x 가이드 :

단계는 다음과 같습니다.

1.) 종속성 Dagger을 위해 build.gradle파일에 추가

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    ...
    compile 'com.squareup.dagger:dagger:1.2.2'
    provided 'com.squareup.dagger:dagger-compiler:1.2.2'

또한에 packaging-option대한 오류를 방지하려면 추가하십시오 duplicate APKs.

android {
    ...
    packagingOptions {
        // Exclude file to avoid
        // Error: Duplicate files during packaging of APK
        exclude 'META-INF/services/javax.annotation.processing.Processor'
    }
}

2)을 생성 Injector을 처리하는 클래스 ObjectGraph.

public enum Injector
{
    INSTANCE;

    private ObjectGraph objectGraph = null;

    public void init(final Object rootModule)
    {

        if(objectGraph == null)
        {
            objectGraph = ObjectGraph.create(rootModule);
        }
        else
        {
            objectGraph = objectGraph.plus(rootModule);
        }

        // Inject statics
        objectGraph.injectStatics();

    }

    public void init(final Object rootModule, final Object target)
    {
        init(rootModule);
        inject(target);
    }

    public void inject(final Object target)
    {
        objectGraph.inject(target);
    }

    public <T> T resolve(Class<T> type)
    {
        return objectGraph.get(type);
    }
}

3.) RootModule미래 모듈을 함께 연결하기 위해 만듭니다 . 주석 injects을 사용할 모든 클래스를 지정 하려면 포함해야합니다 . @Inject그렇지 않으면 Dagger가 RuntimeException.

@Module(
    includes = {
        UtilsModule.class,
        NetworkingModule.class
    },
    injects = {
        MainActivity.class
    }
)
public class RootModule
{
}

4.) 루트에 지정된 모듈 내에 다른 하위 모듈이있는 경우 해당 모듈을 만듭니다.

@Module(
    includes = {
        SerializerModule.class,
        CertUtilModule.class
    }
)
public class UtilsModule
{
}

5.) 생성자 매개 변수로 종속성을받는 리프 모듈을 만듭니다. 제 경우에는 순환 종속성이 없었기 때문에 Dagger가이를 해결할 수 있는지는 모르겠지만 가능성은 낮습니다. 생성자 매개 변수는 Dagger에 의해 모듈에 제공되어야합니다. 지정하면 complete = false다른 모듈에도있을 수 있습니다.

@Module(complete = false, library = true)
public class NetworkingModule
{
    @Provides
    public ClientAuthAuthenticator providesClientAuthAuthenticator()
    {
        return new ClientAuthAuthenticator();
    }

    @Provides
    public ClientCertWebRequestor providesClientCertWebRequestor(ClientAuthAuthenticator clientAuthAuthenticator)
    {
        return new ClientCertWebRequestor(clientAuthAuthenticator);
    }

    @Provides
    public ServerCommunicator providesServerCommunicator(ClientCertWebRequestor clientCertWebRequestor)
    {
        return new ServerCommunicator(clientCertWebRequestor);
    }
}

6) 확장 Application및 초기화 Injector.

@Override
public void onCreate()
{
    super.onCreate();
    Injector.INSTANCE.init(new RootModule());
}

7.) MainActivity에서 onCreate()메서드 의 인젝터를 호출합니다 .

@Override
protected void onCreate(Bundle savedInstanceState)
{
    Injector.INSTANCE.inject(this);
    super.onCreate(savedInstanceState);
    ...

8)를 사용 @Inject하여에서 MainActivity.

public class MainActivity extends ActionBarActivity
{  
    @Inject
    public ServerCommunicator serverCommunicator;

...

오류가 발생 no injectable constructor found하면 @Provides주석을 잊지 않았는지 확인하십시오 .


여기에서 유용한 Dagger2 샘플 프로젝트 및 자습서를 찾을 수 있습니다.

MVP를 사용한 Dagger 2 작업 샘플 프로젝트

비디오 튜토리얼

실용적인 튜토리얼

참고 URL : https://stackoverflow.com/questions/27036933/how-to-set-up-dagger-dependency-injection-from-scratch-in-android-project

반응형