2015-03-28 5 views
27

मैं अपने एंड्रॉइड एप्लिकेशन में डी के लिए डैगर 2 का उपयोग करता हूं। मैंने पाया कि मुझे @Inject फ़ील्ड का उपयोग करने वाले प्रत्येक वर्ग के लिए इंजेक्ट विधि लिखनी है। क्या कोई तरीका है कि मैं सिर्फ माता-पिता वर्ग को इंजेक्ट कर सकता हूं ताकि मुझे प्रत्येक उप-वर्ग पर इंजेक्ट करने की आवश्यकता न हो? उदाहरण के लिए गतिविधि लें। मेरे पास BaseActivity है कि प्रत्येक गतिविधि से विस्तारित होता है। क्या कोई तरीका है कि मैं बेसएक्टिविटी के लिए घटक में एक इंजेक्ट विधि बना सकता हूं और बस बेसएक्टिविटी के ऑनक्रेट में इंजेक्ट कर सकता हूं, और उप गतिविधियों में @ इंजेक्ट फ़ील्ड स्वचालित रूप से इंजेक्शन प्राप्त कर सकते हैं?निर्भरता इंजेक्शन के लिए dagger2 का उपयोग करते समय मैं बस सुपर क्लास इंजेक्ट कर सकता हूं?

+0

में इंजेक्शन विधियों को रखने के लिए अपने नियमों के लिए अगले -keep class <ComponentClass> { *; } जोड़ने की आवश्यकता है, क्या आप अपना उदाहरण दिखाने के लिए कुछ उदाहरण कोड जोड़ सकते हैं? – nhaarman

उत्तर

21

यह अभी नहीं किया जा सकता है। स्पष्टीकरण ग्रेगरी किक द्वारा:

  1. आप किसी भी प्रकार @Inject अपने वर्ग पदानुक्रम में कहीं भी है कि के लिए एक सदस्य इंजेक्शन विधि बना सकते हैं:

    यहाँ कैसे सदस्यों इंजेक्शन तरीके काम है। यदि ऐसा नहीं होता है, तो आपको त्रुटि मिल जाएगी।

  2. सभी @Inject पूरे प्रकार के पदानुक्रम में एड सदस्यों को इंजेक्शन दिया जाएगा: तर्क प्रकार और सभी supertypes।
  3. कोई भी सदस्य तर्क प्रकार के उपप्रकारों के लिए @Inject एड नहीं होगा।

यह समस्या here और here चर्चा की गई, अपडेट के लिए इन का पालन। लेकिन जल्द ही इसे बदलने की संभावना नहीं है, क्योंकि डैगर 2 close to release है।

+0

ऐसा लगता है कि उन्होंने इस कारण को एक कारण के लिए बनाया है। लेकिन यह अभी भी एक दयालु है कि वे इसका समर्थन नहीं करते क्योंकि यह थोड़ा सा अंतर्ज्ञानी IMHO है। फिर भी, जवाब के लिए धन्यवाद! –

+0

@ Chris.Zou सबक्लास इंजेक्शन का समर्थन करने के लिए आपको रनटाइम पर प्रतिबिंब करना होगा। डैगर 2 टीम ने जल्दी ही फैसला किया कि वे रनटाइम पर सामान करने से बचना चाहते हैं, क्योंकि यह धीमा है और जब तक आप ऐप नहीं चलाते हैं तब तक आपको त्रुटियों के बारे में पता नहीं चलता है। – vaughandroid

35

मुझे एक ही स्थिति का सामना करना पड़ा। सभी गतिविधियों में एक आम घटक से थोड़ा इंजेक्शन को कम करने का एक तरीका निम्न है:

1) सामान्य घटक बनाने में सक्षम होने के लिए एप्लिकेशन क्लास को विस्तारित करें और इसका संदर्भ रखें।

public class ApplicationDagger extends Application { 

    private ApplicationComponent component; 

    @Override 
    public void onCreate(){ 
     super.onCreate(); 
     component = DaggerApplicationComponent.builder().applicationModule(new ApplicationModule(this)).build(); 
    } 

    public ApplicationComponent getComponent(){ 
      return component; 
    } 
} 

2) एक सार DaggerActivity जो आवेदन से सामान्य घटक हो जाता है और एक सार विधि injectActivity कहता है, एक तर्क के रूप घटक देने बनाएँ। इस तरह:

public abstract class DaggerActivity extends Activity { 

    @Override 
    public void onCreate(Bundle saved){ 
     super.onCreate(saved); 
     ApplicationComponent component = ((ApplicationDagger) getApplication()).getComponent(); 
     injectActivity(component); 
    } 

    public abstract void injectActivity(ApplicationComponent component); 
} 

3) अंतिम, आप वास्तव में इंजेक्षन करने के लिए प्रत्येक Activity विस्तार DaggerActivity है। लेकिन अब इसे कम प्रयासों के साथ किया जा सकता है, क्योंकि आपको abstract विधि को लागू करना है अन्यथा आपको संकलन त्रुटियां मिलेंगी। यहां हम जाते हैं:

public class FirstActivity extends DaggerActivity { 

    @Inject 
    ClassToInject object; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     //initialize your Activity 
    } 

    @Override 
    public void injectActivity(ApplicationComponent component) { 
     component.inject(this); 
    } 
} 

बेशक, आपको अभी भी प्रत्येक घटक को अपने घटक में स्पष्ट रूप से घोषित करना होगा।

अद्यतन: इंजेक्शन @ActivityScope टुकड़ों में वस्तुओं

कुछ बिंदु पर, मैं custom scopes उपयोग करने के लिए एक Activity जीवन चक्र के लिए वस्तुओं बाध्य करने के लिए की जरूरत है। मैंने इस पोस्ट को विस्तारित करने का फैसला किया क्योंकि यह कुछ लोगों की मदद कर सकता है।

मान लीजिए कि आप एक @Module वर्ग ActivityModule और एक @Subcomponent इंटरफ़ेस ActivityComponent करते हैं।

आपको DaggerActivity को संशोधित करने की आवश्यकता होगी। ActivitiesDaggerActivity को विस्तारित करने के लिए नई विधि (हस्ताक्षर में परिवर्तन) को लागू करने की आवश्यकता होगी।

public abstract class ActivityDagger extends AppCompatActivity { 

    ComponentActivity component; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     component = ((ApplicationDagger) getApplication()).getComponent().plus(new ActivityModule(this)); 
     injectActivity(component); 
     super.onCreate(savedInstanceState); 
    } 

    ActivityComponent getComponent() { 
     return component; 
    } 

    public abstract void injectActivity(ActivityComponent component); 
} 

फिर, एक वर्ग FragmentDaggerFragment का विस्तार इस तरह बनाया जा सकता है:

public abstract class FragmentDagger extends Fragment { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     ActivityDagger activityDagger = (ActivityDagger) getActivity(); 
     ActivityComponent component = activityDagger.getComponent(); 
     injectFragment(component); 
    } 

    public abstract void injectFragment(ActivityComponent component); 

} 

Activities का सवाल है, FragmentsFragmentDagger विस्तार लागू करने के लिए केवल एक ही तरीके होते है:

public abstract void injectFragment(ActivityComponent component); 

जहां भी आप चाहें Fragments का पुन: उपयोग करने में सक्षम होना चाहिए। ध्यान दें कि विधि super.onCreated()ActivityDagger में घटक तत्काल के बाद बुलाया जाना चाहिए। अन्यथा, आपको NullPointerException मिलेगा जब Activity स्थिति पुनर्निर्मित की जाएगी, क्योंकि Fragment की विधि को कॉल किया जाएगा।

+0

टिप के लिए धन्यवाद! –

2

आप प्रतिबिंब का उपयोग कर एक छोटे से हैक कर सकते हैं:

public class UiInjector { 
 

 
    private static final String METHOD_NAME = "inject"; 
 

 
    private final UIComponent component; 
 

 
    public UiInjector(final UIComponent component) { 
 
     this.component = component; 
 
    } 
 

 
    public void inject(final Object subject) { 
 
     try { 
 
      component.getClass() 
 
        .getMethod(METHOD_NAME, subject.getClass()) 
 
        .invoke(component, subject); 
 
     } catch (final NoSuchMethodException exception) { 
 
      throwNoInjectMethodForType(component, subject.getClass()); 
 
     } catch (final Exception exception) { 
 
      throwUnknownInjectionError(exception); 
 
     } 
 
    } 
 

 
    private void throwNoInjectMethodForType(final Object component, final Class subjectType) { 
 
     throw new RuntimeException(component.getClass().getSimpleName() + 
 
       " doesn't have inject method with parameter type : " + subjectType); 
 
    } 
 

 
    private void throwUnknownInjectionError(final Exception cause) { 
 
     throw new RuntimeException("Unknown injection error", cause); 
 
    } 
 
}

इस मामले में, आप अभी भी एक घटक में विधि इंजेक्षन लिखने की ज़रूरत है, लेकिन आप 'सुई' की जरूरत नहीं है प्रत्येक गतिविधि, खंड, दृश्य, जो कुछ भी में विधि।

यह क्यों काम करता है? जब हम इंजेक्शन विषय पर getClass() का उपयोग करते हैं तो आधार पर आधार नहीं मिलेगा।

सावधानी! यदि आप प्रोगार्ड का उपयोग करते हैं, तो आपको घटक

संबंधित मुद्दे