डैगर 2 में एक घटक (ऑब्जेक्ट ग्राफ) के जीवनचक्र को निर्धारित करता है?


134

मैं डैगर 2 में अपने सिर को चारों ओर लपेटने की कोशिश कर रहा हूं, विशेष रूप से स्कोप ग्राफ का जीवनचक्र। आप एक घटक कैसे बना सकते हैं जो गुंजाइश छोड़ने पर साफ हो जाएगा।

एंड्रॉइड एप्लिकेशन के मामले में, डैगर 1.x का उपयोग करने से आपके पास आमतौर पर एप्लिकेशन स्तर पर एक रूट स्कोप होता है जिसे आप गतिविधि स्तर पर एक चाइल्ड स्कोप बनाने के लिए विस्तारित करेंगे।

public class MyActivity {

    private ObjectGraph mGraph;

    public void onCreate() {
        mGraph = ((MyApp) getApplicationContext())
            .getObjectGraph()
            .plus(new ActivityModule())
            .inject(this);
    }

    public void onDestroy() {
        mGraph = null;
    }
}

जब तक आप इस बात का संदर्भ रखते हैं, तब तक बच्चे की गुंजाइश मौजूद होती है, जो इस मामले में आपकी गतिविधि का जीवनचक्र था। OnDestroy में संदर्भ को छोड़ने से यह सुनिश्चित हो जाता है कि स्कोप किया गया ग्राफ कचरा एकत्र करने के लिए स्वतंत्र था।

संपादित करें

जेसी विल्सन ने हाल ही में एक मैया पुलक पोस्ट किया

डैगर 1.0 ने इसके स्कोप नाम को बुरी तरह से खराब कर दिया ... @ सिलिंगटन एनोटेशन का उपयोग रूट ग्राफ़ और कस्टम ग्राफ़ दोनों के लिए किया जाता है, इसलिए यह पता लगाना मुश्किल है कि किसी चीज़ का वास्तविक दायरा क्या है।

और बाकी सब कुछ मैंने डैगर 2 के बारे में पढ़ा / सुना है, जिस तरह से काम करने के तरीके में सुधार हुआ है, लेकिन मैं अंतर को समझने के लिए संघर्ष कर रहा हूं। नीचे @Kirill Boyarshinov की टिप्पणी के अनुसार, एक घटक या निर्भरता का जीवनचक्र अभी भी, हमेशा की तरह ठोस संदर्भों द्वारा निर्धारित किया जाता है। तो क्या डैगर 1.x और 2.0 स्कोप के बीच का अंतर विशुद्ध रूप से अर्थ स्पष्टता का मामला है?

मेरी समझ

खंजर 1.x

निर्भरताएँ थीं @Singletonया नहीं। यह रूट ग्राफ और उपग्रहों में निर्भरता के लिए समान रूप से सत्य था, जिससे अस्पष्टता का ग्राफ बढ़ता था, जिस पर निर्भरता ग्राफ के लिए बाध्य था (देखें कि इन-डैगर सिंगल ग्राफ़ में उप-ग्राफ़ कैश्ड हैं या क्या वे हमेशा फिर से बनाए जाएंगे जब एक नई गतिविधि उप-ग्राफ़ निर्माण किया गया है; )

खंजर 2.0

कस्टम स्कोप आपको शब्दार्थ स्पष्ट स्कोप बनाने की अनुमति देते हैं, लेकिन कार्यात्मक रूप से @Singletonडैगर 1.x में आवेदन करने के बराबर हैं।

// Application level
@Singleton
@Component( modules = MyAppModule.class )
public interface MyAppComponent {
    void inject(Application app);
}

@Module
public class MyAppModule {

    @Singleton @Named("SingletonScope") @Provides
    StringBuilder provideStringBuilderSingletonScope() {
        return new StringBuilder("App");
    }
}

// Our custom scope
@Scope public @interface PerActivity {}

// Activity level
@PerActivty
@Component(
    dependencies = MyAppComponent.class,
    modules = MyActivityModule.class
)
public interface MyActivityComponent {
    void inject(Activity activity);
}

@Module
public class MyActivityModule {

    @PerActivity @Named("ActivityScope") @Provides
    StringBuilder provideStringBuilderActivityScope() {
        return new StringBuilder("Activity");
    }

    @Name("Unscoped") @Provides
    StringBuilder provideStringBuilderUnscoped() {
        return new StringBuilder("Unscoped");
    }
}

// Finally, a sample Activity which gets injected
public class MyActivity {

    private MyActivityComponent component;

    @Inject @Named("AppScope")
    StringBuilder appScope

    @Inject @Named("ActivityScope")
    StringBuilder activityScope1

    @Inject @Named("ActivityScope")
    StringBuilder activityScope2

    @Inject @Named("Unscoped")
    StringBuilder unscoped1

    @Inject @Named("Unscoped")
    StringBuilder unscoped2

    public void onCreate() {
        component = Dagger_MyActivityComponent.builder()
            .myApplicationComponent(App.getComponent())
            .build()
            .inject(this);

        appScope.append(" > Activity")
        appScope.build() // output matches "App (> Activity)+" 

        activityScope1.append("123")
        activityScope1.build() // output: "Activity123"

        activityScope2.append("456")
        activityScope1.build() // output: "Activity123456"

        unscoped1.append("123")
        unscoped1.build() // output: "Unscoped123"

        unscoped2.append("456")
        unscoped2.build() // output: "Unscoped456"

    }

    public void onDestroy() {
        component = null;
    }

}

Takeaway जा रहा है कि इस घटक के जीवन चक्र के बारे में @PerActivityअपने इरादे का उपयोग संचार , लेकिन अंत में आप कहीं भी / कभी भी घटक का उपयोग कर सकते हैं। डैगर का एकमात्र वादा यह है कि, किसी दिए गए घटक के लिए, स्कोप एनोटेट किए गए तरीके एकल उदाहरण लौटाएंगे। मुझे यह भी लगता है कि डैगर 2 घटक पर सत्यापन एनोटेशन का उपयोग करता है यह सत्यापित करने के लिए कि मॉड्यूल केवल निर्भरता प्रदान करते हैं जो या तो एक ही दायरे में हैं या गैर-स्कोप किए गए हैं।

संक्षेप में

निर्भरताएं अभी भी सिंगलटन या नॉन-सिंगलटन हैं, लेकिन @Singletonअब एप्लीकेशन-लेवल सिंगलटन इंस्टेंस के लिए है और कस्टम स्कोप्स एक छोटे जीवनचक्र के साथ सिंगलटन निर्भरता की घोषणा करने के लिए पसंदीदा तरीका है।

डेवलपर उन संदर्भों को छोड़ने के लिए घटकों / निर्भरता के जीवनचक्र के प्रबंधन के लिए जिम्मेदार है जिनकी अब आवश्यकता नहीं है और यह सुनिश्चित करने के लिए जिम्मेदार हैं कि घटकों को केवल एक बार उस दायरे में बनाया जाता है जिसके लिए उनका इरादा है, लेकिन कस्टम गुंजाइश एनोटेशन से उस दायरे की पहचान करना आसान हो जाता है ।

$ 64k प्रश्न *

क्या डैगर 2 स्कोप और जीवनचक्र की मेरी समझ सही है?

* वास्तव में $ 64'000 का सवाल नहीं है।


5
तुम कुछ भी नहीं याद किया। प्रत्येक घटक के लाइव साइकिल का प्रबंधन मैनुअल है। मेरे अपने अनुभव से भी डैगर 1 में ऐसा ही था। जब plus()नए ग्राफ के संदर्भ का उपयोग करके अनुप्रयोग स्तर ObjectGraph ऑब्जेक्ट को सबग्राफ करने के लिए गतिविधि में संग्रहीत किया गया था, और इसके लाइव साइकिल (dereferenced in onDestroy) के लिए बाध्य था । स्कोप के रूप में, वे सुनिश्चित करते हैं कि आपके घटक कार्यान्वयन संकलन समय पर त्रुटियों के बिना उत्पन्न होते हैं, प्रत्येक निर्भरता संतुष्ट होने के साथ। तो यह सिर्फ प्रलेखन उद्देश्यों के लिए नहीं है। इस थ्रेड से कुछ उदाहरण देखें ।
किरिल बोयारशिनोव

1
बस इस पर स्पष्ट होने के लिए, "अनकैप्ड" प्रदाता तरीके हर इंजेक्शन पर नए उदाहरण देते हैं?
user1923613

2
आप घटक क्यों सेट करते हैं = अशक्त; onDestroy () में?
मरिअन पौडज़िओच

जवाबों:


70

अपने प्रश्न के लिए के रूप में

डैगर 2 में एक घटक (ऑब्जेक्ट ग्राफ) के जीवनचक्र को निर्धारित करता है?

संक्षिप्त उत्तर आप इसे निर्धारित करते हैं । आपके घटकों को एक गुंजाइश दी जा सकती है, जैसे कि

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

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

ये आपके लिए दो चीजों के लिए उपयोगी हैं:

  • स्कोप की वैधता: एक घटक में केवल अनकैप्ड प्रदाता हो सकते हैं, या आपके घटक के समान स्कोप वाले प्रदाता हो सकते हैं।

@Component(modules={ApplicationModule.class})
@ApplicationScope
public interface ApplicationComponent {
    Something something();
    AnotherThing anotherThing();

    void inject(Whatever whatever);
}

@Module
public class ApplicationModule {
    @ApplicationScope //application-scoped provider, only one can exist per component
    @Provides
    public Something something() {
         return new Something();
    }

    @Provides //unscoped, each INJECT call creates a new instance
    public AnotherThing anotherThing() {
        return new AnotherThing();
    }
}
  • आपके स्कोप्ड निर्भरता को उप-स्कोप करने की अनुमति देता है, इस प्रकार आपको "सब्सक्रॉप्ड" घटक बनाने की अनुमति देता है जो "सुपरस्क्रॉप्ड" घटक से प्रदान किए गए इंस्टेंस का उपयोग करता है।

यह @Subcomponentएनोटेशन, या घटक निर्भरता के साथ किया जा सकता है । मैं व्यक्तिगत रूप से निर्भरता पसंद करता हूं।

@Component(modules={ApplicationModule.class})
@ApplicationScope
public interface ApplicationComponent {
    Something something();
    AnotherThing anotherThing();

    void inject(Whatever whatever);

    ActivityComponent newActivityComponent(ActivityModule activityModule); //subcomponent factory method
}

@Subcomponent(modules={ActivityModule.class})
@ActivityScope
public interface ActivityComponent {
    ThirdThingy thirdThingy();

    void inject(SomeActivity someActivity);
}

@Module
public class ActivityModule {
    private Activity activity;

    public ActivityModule(Activity activity) {
        this.activity = activity;
    }

    //...
}

ApplicationComponent applicationComponent = DaggerApplicationComponent.create();
ActivityComponent activityComponent = applicationComponent.newActivityComponent(new ActivityModule(SomeActivity.this));

या आप इस तरह घटक निर्भरता का उपयोग कर सकते हैं

@Component(modules={ApplicationModule.class})
@ApplicationScope
public class ApplicationComponent {
    Something something(); 
    AnotherThing anotherThing();

    void inject(Whatever whatever);
}

@Component(dependencies={ApplicationComponent.class}, modules={ActivityModule.class})
@ActivityScope
public interface ActivityComponent extends ApplicationComponent {
    ThirdThingy thirdThingy();

    void inject(SomeActivity someActivity);
}

@Module
public class ActivityModule {
    private Activity activity;

    public ActivityModule(Activity activity) {
        this.activity = activity;
    }

    //...
}

ApplicationComponent applicationComponent = DaggerApplicationComponent.create();
ActivityComponent activityComponent = DaggerActivityComponent.builder().activityModule(new ActivityModule(SomeActivity.this)).build();

जानने के लिए महत्वपूर्ण बातें:

  • एक स्कॉप्ड प्रदाता प्रत्येक घटक के लिए दिए गए क्षेत्र के लिए एक उदाहरण बनाता है । मतलब एक घटक अपने स्वयं के उदाहरणों पर नज़र रखता है, लेकिन अन्य घटकों में साझा गुंजाइश पूल या कुछ जादू नहीं है। किसी दिए गए दायरे में एक उदाहरण के लिए, आपको घटक के एक उदाहरण की आवश्यकता है। यही कारण है कि आपको ApplicationComponentअपने स्वयं के स्कोप्ड निर्भरता तक पहुंचने के लिए प्रदान करना होगा ।

  • एक घटक केवल एक स्कोप किए गए घटक को सब्सक्राइब कर सकता है। एकाधिक स्कॉप्ड घटक निर्भरता की अनुमति नहीं है।


एक घटक केवल एक स्कोप किए गए घटक को सब्सक्राइब कर सकता है। एकाधिक स्कॉप्ड घटक निर्भरता की अनुमति नहीं है (भले ही वे सभी अलग-अलग स्कोप नहीं हैं, हालांकि मुझे लगता है कि यह एक बग है)। वास्तव में समझ में नहीं आता कि इसका क्या अर्थ है
डेमन युआन

लेकिन livecycle का क्या। यदि गतिविधि नष्ट हो जाती है तो क्या गतिविधिकॉम्प्लेंट कचरा उठाने वाले के लिए होगा?
गंभीर

यदि आप इसे कहीं और स्टोर नहीं करते हैं तो हां
एपिकपांडफर्सेज

1
इसलिए अगर हमें गतिविधि के माध्यम से घटक की आवश्यकता होती है और इंजेक्शन वाली वस्तु जीवित रहती है तो हम गतिविधि के अंदर घटक का निर्माण करते हैं। अगर हम केवल एक टुकड़े के माध्यम से जीवित रहना चाहते हैं, तो मुझे टुकड़े के अंदर घटक का निर्माण करना चाहिए, है ना? जहां आप रखते हैं घटक उदाहरण गुंजाइश बनाता है?
थ्रेशियन

यदि मैं इसे किसी विशिष्ट गतिविधि के माध्यम से जीवित रखना चाहता हूं तो मुझे क्या करना चाहिए?
थ्रेशियन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.