Android परियोजना में खरोंच से DAGGER निर्भरता इंजेक्शन कैसे स्थापित करें?


100

डैगर का उपयोग कैसे करें? मेरे एंड्रॉइड प्रोजेक्ट में काम करने के लिए डैगर को कैसे कॉन्फ़िगर करें?

मैं अपने एंड्रॉइड प्रोजेक्ट में डैगर का उपयोग करना चाहता हूं, लेकिन मुझे यह भ्रामक लगता है।

संपादित करें: Dagger2 भी 2015 04 15 के बाद से बाहर है, और यह और भी भ्रामक है!

[यह सवाल एक "ठूंठ" है, जिस पर मैं अपने जवाब को जोड़ रहा हूं क्योंकि मैंने Dagger1 के बारे में अधिक सीखा, और Dagger2 के बारे में और जानें। यह प्रश्न "प्रश्न" के बजाय मार्गदर्शक का अधिक है ।]


इसे भी देखें: stackoverflow.com/a/40546157/2413303
EpicPandaForce

इसे साझा करने के लिए धन्यवाद। क्या आपके पास ViewModel वर्गों को इंजेक्ट करने के बारे में ज्ञान है? मेरा ViewModel वर्ग किसी भी @AssistedInject के बिना है, लेकिन इसमें निर्भरताएं हैं जो डैगर ग्राफ द्वारा प्रदान की जा सकती हैं?
AndroidDev

1
ज़रूर देखें, stackoverflow.com/questions/60884402/…
EpicPandaForce

एक और सवाल, डैगर 2 के साथ, क्या किसी वस्तु का होना संभव है और यह संदर्भ द्वारा साझा किया गया है ViewModelऔर PageKeyedDataSource? जैसे मैं RxJava2 का उपयोग करता हूं, और चाहता हूं कि दोनों वर्गों द्वारा कॉम्पोजिटडायोसपिटल साझा किया जाए और यदि उपयोगकर्ता बैक बटन दबाए, तो मैं डिस्पोजेबल ऑब्जेक्ट को साफ करना चाहता हूं। मैंने यहाँ जोड़ा मामला दर्ज किया: stackoverflow.com/questions/62595956/…
AndroidDev

आप बेहतर कर रहे हैं कि समग्र ViewModelकंपोजिटरी को अंदर रखना बंद कर दें और हो सकता है कि आपके कस्टम पेजकेयेडडॉटसोर्स के कंस्ट्रक्टर तर्क के रूप में एक ही कंपोजिटोसेप्टिक पास हो, लेकिन मैं वास्तव में उस हिस्से के लिए डैगर का उपयोग नहीं करूंगा क्योंकि तब आपको सब -कॉपी किए गए सब-कॉम्प्लेक्टर्स की आवश्यकता होती है, और हेल्ट वास्तव में समर्थन नहीं करेगा तुम्हारे लिए आसान।
एपिकपांडाफॉर्स

जवाबों:


193

डैगर 2.x के लिए गाइड (संशोधित संस्करण 6) :

चरण निम्नलिखित हैं:

1.)Dagger अपनी 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()
    }
}
  • एप्लिकेशन स्तर बिल्ड.ग्रेड :

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}डैगर एक्सएक्सएक्स में समान है :

@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() {
    }
}

आपको इंटरफ़ेस के साथ विशिष्ट कार्यान्वयन को "बाइंड" करना होगा @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)

(नोट: एपीटी का उपयोग करके बिल्डर वर्ग 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();
    }
}

कृपया ध्यान दें कि केवल एक स्कॉप्ड घटक को एक निर्भरता के रूप में निर्दिष्ट किया जा सकता है। इसे ठीक उसी तरह से सोचें जैसे जावा में मल्टीपल इनहेरिटेंस का समर्थन नहीं किया गया है।

+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 के बारे में अन्य स्टैक ओवरफ्लो प्रश्नों की जांच करें, वे बहुत सारी जानकारी प्रदान करते हैं। उदाहरण के लिए, इस उत्तर में मेरी वर्तमान Dagger2 संरचना निर्दिष्ट है ।

धन्यवाद

Github , TutsPlus , Joe Steele , Froger MCS और Google के मार्गदर्शकों के लिए धन्यवाद ।

इसके अलावा इस कदम से कदम प्रवास गाइड मैं इस पोस्ट लिखने के बाद मिला।

और किरिल द्वारा गुंजाइश की व्याख्या के लिए ।

आधिकारिक दस्तावेज में और भी अधिक जानकारी ।


मुझे विश्वास है कि हम DaggerApplicationComponent के कार्यान्वयन को याद कर रहे हैं
थानासिस कपेलोनीस

1
DaggerApplicationComponentबिल्ड पर APT द्वारा @ThanasisKapelonis को ऑटोजेनर किया गया है, लेकिन मैं इसे जोड़ूंगा ।
एपिकपांडाफर्स

1
मुझे बस विधि को सार्वजनिक करना था Injector.initializeApplicationComponent क्योंकि मेरा CustomApplication पैकेज के दायरे से बाहर था और सब कुछ सही काम करता है! धन्यवाद!
जुआन साराविया २ Sar

2
थोड़ा देर से लेकिन शायद निम्नलिखित उदाहरण किसी की मदद करेंगे: github.com/dawidgdanski/android-compass-api github.com/dawidgdanski/Bakery
dawid gdanski

1
यदि आपको 'चेतावनी: एनोटेशन प्रोसेसिंग के लिए असंगत प्लगइन्स का उपयोग करना: Android-apt। इससे अप्रत्याशित व्यवहार हो सकता है। ' चरण 1 में, apt 'com.google.dagger: dagger-compiler: 2.7' को annotationProcessor 'com.google.dagger: dagger-compiler: 2.7' में बदलें और सभी apt config निकालें। विवरण यहाँ पाया जा सकता है bitbucket.org/hvisser/android-apt/wiki/Migration
thanhbinh84

11

डैगर 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एनोटेशन का उपयोग करेंगे , क्योंकि अन्यथा डैगर फेंकता है RuntimeException

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

4.) यदि आपके रूट में निर्दिष्ट मॉड्यूल के भीतर आपके अन्य उप-मॉड्यूल हैं, तो उन लोगों के लिए मॉड्यूल बनाएं:

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

5.) पत्ती मॉड्यूल का निर्माण करें जो निर्माण मापदंडों के रूप में निर्भरता प्राप्त करते हैं। मेरे मामले में, कोई परिपत्र निर्भरता नहीं थी, इसलिए मुझे नहीं पता कि क्या डैगर इसे हल कर सकते हैं, लेकिन मुझे इसकी संभावना नहीं है। निर्माता पैरामीटर को डैगर द्वारा एक मॉड्यूल में भी प्रदान किया जाना चाहिए, यदि आप निर्दिष्ट करते हैं 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एनोटेशन को नहीं भूले हैं।


यह उत्तर आंशिक रूप से उत्पन्न कोड के आधार पर है Android Bootstrap। तो, उन्हें यह पता लगाने के लिए क्रेडिट। समाधान का उपयोग करता है Dagger v1.2.2
एपिकपांडाफायर 12

3
की गुंजाइश dagger-compilerहोनी चाहिए providedअन्यथा इसे आवेदन में शामिल किया जाएगा, और यह जीपीएल लाइसेंस के तहत है।
डेनिस नियाज़ेव

@deniskniazhev ओह, मुझे नहीं पता था कि! सर उठाने के लिए धन्यवाद!
एपिकपांडाफार्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.