Android ऐप्लिकेशन में डैगर का इस्तेमाल करना

डैगर की बुनियादी बातें पेज पर बताया गया है कि डैगर, डिपेंडेंसी को ऑटोमेट करने में कैसे मदद कर सकता है इंजेक्शन हुआ हो. डैगर के साथ, आपको कुछ भी लिखना नहीं पड़ता ऐसा बॉयलरप्लेट कोड जहां गड़बड़ी का पता चलता है.

सबसे सही तरीकों के बारे में खास जानकारी

  • डैगर में टाइप जोड़ने के लिए, @Inject के साथ कंस्ट्रक्टर इंजेक्शन का इस्तेमाल करें ग्राफ़ पर क्लिक करें. जब ऐसा न हो:
    • डैगर को यह बताने के लिए @Binds का इस्तेमाल करें कि किसी इंटरफ़ेस में कौनसा तरीका लागू होना चाहिए.
    • @Provides का इस्तेमाल करके, डैगर को अपने प्रोजेक्ट की क्लास उपलब्ध कराने का तरीका बताएं स्वामी नहीं है.
  • आपको कॉम्पोनेंट में सिर्फ़ एक बार मॉड्यूल के बारे में बताना चाहिए.
  • स्कोप एनोटेशन को इस आधार पर नाम दें कि एनोटेशन का इस्तेमाल किया जाता है. उदाहरण के लिए: @ApplicationScope, @LoggedUserScope, और @ActivityScope.

डिपेंडेंसी जोड़ना

अपने प्रोजेक्ट में डैगर का इस्तेमाल करने के लिए, इन डिपेंडेंसी को अपने ऐप्लिकेशन में जोड़ें आपकी build.gradle फ़ाइल. आपको डैगर का नया वर्शन मिल सकता है इस GitHub प्रोजेक्ट में.

Kotlin

plugins {
  id 'kotlin-kapt'
}

dependencies {
    implementation 'com.google.dagger:dagger:2.x'
    kapt 'com.google.dagger:dagger-compiler:2.x'
}

Java

dependencies {
    implementation 'com.google.dagger:dagger:2.x'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.x'
}

Android में डैगर

उदाहरण के तौर पर, पहली इमेज में दिए गए डिपेंडेंसी ग्राफ़ के साथ Android ऐप्लिकेशन का कोई उदाहरण देखें.

लॉगिन ऐक्टिविटी,LoginViewModel पर निर्भर करती है, जो UserRepository पर निर्भर करती है,
  जो UserLocalDataSource और UserRemoteDataSource पर निर्भर करता है
  यह Retrofit पर निर्भर करता है.

पहला डायग्राम. उदाहरण का डिपेंडेंसी ग्राफ़ कोड

Android में, आप आमतौर पर एक डैगर ग्राफ़ बनाते हैं, जो आपके ऐप्लिकेशन में मौजूद होता है क्लास का इस्तेमाल करें, क्योंकि आप ग्राफ़ के एक इंस्टेंस को ऐप चल रहा है. इस तरह से, ग्राफ़ ऐप्लिकेशन के लाइफ़साइकल से जुड़ा होता है. कुछ मामलों में, हो सकता है कि आप ऐप्लिकेशन के संदर्भ को ग्राफ़. इसके लिए, आपको ग्राफ़ को Application क्लास. इसका एक फ़ायदा यह है यह ग्राफ़ अन्य Android फ़्रेमवर्क क्लास के लिए भी उपलब्ध है. इसके अलावा, यह आपको कस्टम टेस्ट में Application क्लास.

ग्राफ़ जनरेट करने वाले इंटरफ़ेस की @Component के साथ व्याख्या की गई है, तो उसे ApplicationComponent या ApplicationGraph कहा जा सकता है. आम तौर पर, आपकी कस्टम Application क्लास में उस कॉम्पोनेंट का एक इंस्टेंस और उसे कॉल करें जब भी आपको ऐप्लिकेशन ग्राफ़ की ज़रूरत हो, जैसा कि नीचे दिए गए कोड में दिखाया गया है snippet:

Kotlin

// Definition of the Application graph
@Component
interface ApplicationComponent { ... }

// appComponent lives in the Application class to share its lifecycle
class MyApplication: Application() {
    // Reference to the application graph that is used across the whole app
    val appComponent = DaggerApplicationComponent.create()
}

Java

// Definition of the Application graph
@Component
public interface ApplicationComponent {
}

// appComponent lives in the Application class to share its lifecycle
public class MyApplication extends Application {

    // Reference to the application graph that is used across the whole app
    ApplicationComponent appComponent = DaggerApplicationComponent.create();
}

क्योंकि कुछ Android फ़्रेमवर्क क्लास, जैसे कि ऐक्टिविटी और फ़्रैगमेंट सिस्टम से इंस्टैंशिएट होने पर, डैगर आपके लिए उन्हें नहीं बना सकते. गतिविधियों के लिए खास तौर पर, किसी भी इनिशलाइज़ेशन कोड को onCreate() तरीके में जाना होगा. इसका मतलब है कि आप इसके कंस्ट्रक्टर में, @Inject एनोटेशन का इस्तेमाल नहीं कर सकते क्लास (कन्स्ट्रक्टर इंजेक्शन) की खोज करें, जैसा कि आपने पिछले उदाहरणों में किया था. इसके बजाय, तो आपको फ़ील्ड इंजेक्शन का इस्तेमाल करना होगा.

डिपेंडेंसी बनाने के बजाय, onCreate() में किसी ऐक्टिविटी की ज़रूरत होती है तरीका है, तो आपको डैगर से उन डिपेंडेंसी को अपने-आप भरना होगा. फ़ील्ड के लिए इंजेक्शन का इस्तेमाल करते हैं, तो आप इसके बजाय उन फ़ील्ड में @Inject एनोटेशन लागू करें डैगर ग्राफ़ से पाना चाहते हैं.

Kotlin

class LoginActivity: Activity() {
    // You want Dagger to provide an instance of LoginViewModel from the graph
    @Inject lateinit var loginViewModel: LoginViewModel
}

Java

public class LoginActivity extends Activity {

    // You want Dagger to provide an instance of LoginViewModel from the graph
    @Inject
    LoginViewModel loginViewModel;
}

आसानी से इस्तेमाल करने के लिए, LoginViewModel एक Android आर्किटेक्चर कॉम्पोनेंट नहीं है ViewModel; यह सिर्फ़ एक रेगुलर क्लास है जो ViewModel की तरह काम करती है. इन क्लास को इंजेक्ट करने के तरीके के बारे में ज़्यादा जानने के लिए, यह कोड देखें Android ब्लूप्रिंट डैगर के इस्तेमाल के दौरान, डेवलपर-डैगर ब्रांच.

डैगर के साथ एक ज़रूरी बात यह भी है कि इंजेक्ट किए गए फ़ील्ड निजी नहीं हो सकते. उनके पास कम से कम पैकेज-प्राइवेट फ़ॉर्मैट मौजूद होना चाहिए, जैसा कि पिछले कोड में दिखाया गया है.

इंजेक्ट करने से जुड़ी गतिविधियां

डैगर को यह जानने की ज़रूरत है कि LoginActivity को ग्राफ़ तक पहुंचना होगा, ताकि अपनी ज़रूरत के हिसाब से ViewModel उपलब्ध कराएं. डैगर की सामान्य जानकारी वाले पेज पर, आपने ग्राफ़ से ऑब्जेक्ट पाने के लिए, @Component इंटरफ़ेस के रिटर्न टाइप के साथ फ़ंक्शन दिखाकर आपको ग्राफ़. इस मामले में, आपको डैगर को एक ऑब्जेक्ट (LoginActivity) के बारे में बताना होगा इस मामले में) को डिपेंडेंसी इंजेक्ट करने की ज़रूरत होती है. इसके लिए, अगर किसी को एक फ़ंक्शन जो इंजेक्शन का अनुरोध करने वाले ऑब्जेक्ट को पैरामीटर के तौर पर लेता है.

Kotlin

@Component
interface ApplicationComponent {
    // This tells Dagger that LoginActivity requests injection so the graph needs to
    // satisfy all the dependencies of the fields that LoginActivity is requesting.
    fun inject(activity: LoginActivity)
}

Java

@Component
public interface ApplicationComponent {
    // This tells Dagger that LoginActivity requests injection so the graph needs to
    // satisfy all the dependencies of the fields that LoginActivity is injecting.
    void inject(LoginActivity loginActivity);
}

यह फ़ंक्शन डैगर को बताता है कि LoginActivity ग्राफ़ को ऐक्सेस करना चाहता है और इंजेक्शन का अनुरोध करता है. डैगर को उन सभी निर्भरताओं को पूरा करना होगा जो LoginActivity के लिए ज़रूरी है (LoginViewModel अपनी डिपेंडेंसी के साथ). अगर आपके पास ऐसी कई क्लास हैं जिनमें इंजेक्शन का अनुरोध किया जाता है, तो उन सभी को कॉम्पोनेंट में उनके सटीक टाइप के साथ एलान करें. उदाहरण के लिए, अगर आपके पास LoginActivity और RegistrationActivity ने इंजेक्शन का अनुरोध किया है, आपने दो दोनों मामलों को कवर करने वाले सामान्य तरीके के बजाय, inject() तरीके इस्तेमाल करें. सामान्य inject() तरीका, डैगर को यह नहीं बताता कि क्या जानकारी देनी है. फ़ंक्शन इंटरफ़ेस का कोई भी नाम हो सकता है, लेकिन उसे inject() कॉल करने पर, पैरामीटर के रूप में इंजेक्ट करने के लिए ऑब्जेक्ट प्राप्त करना, डैगर में एक कन्वेंशन है.

गतिविधि में कोई ऑब्जेक्ट इंजेक्ट करने के लिए, आपकोappComponent आपकी Application क्लास और inject() मेथड को कॉल करें, जो कि एक इंस्टेंस में पास हो रहा है इंजेक्शन का अनुरोध करने वाली गतिविधि के बारे में.

गतिविधियों का उपयोग करते समय, डैगर को इसमें समस्याओं से बचने के लिए, super.onCreate() को कॉल करने से पहले गतिविधि का onCreate() तरीका फ़्रैगमेंट रीस्टोर करने की सुविधा मिलती है. super.onCreate() में, डेटा वापस लाने की प्रोसेस के दौरान, एक गतिविधि में ऐसे फ़्रैगमेंट अटैच किए जाते हैं जो गतिविधि बाइंडिंग को ऐक्सेस करना चाहते हैं.

फ़्रैगमेंट का इस्तेमाल करते समय, फ़्रैगमेंट के onAttach() में डैगर को इंजेक्ट करें तरीका. इस स्थिति में, super.onAttach() पर कॉल करने से पहले या बाद में ऐसा किया जा सकता है.

Kotlin

class LoginActivity: Activity() {
    // You want Dagger to provide an instance of LoginViewModel from the graph
    @Inject lateinit var loginViewModel: LoginViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        // Make Dagger instantiate @Inject fields in LoginActivity
        (applicationContext as MyApplication).appComponent.inject(this)
        // Now loginViewModel is available

        super.onCreate(savedInstanceState)
    }
}

// @Inject tells Dagger how to create instances of LoginViewModel
class LoginViewModel @Inject constructor(
    private val userRepository: UserRepository
) { ... }

Java

public class LoginActivity extends Activity {

    // You want Dagger to provide an instance of LoginViewModel from the graph
    @Inject
    LoginViewModel loginViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // Make Dagger instantiate @Inject fields in LoginActivity
        ((MyApplication) getApplicationContext()).appComponent.inject(this);
        // Now loginViewModel is available

        super.onCreate(savedInstanceState);
    }
}

public class LoginViewModel {

    private final UserRepository userRepository;

    // @Inject tells Dagger how to create instances of LoginViewModel
    @Inject
    public LoginViewModel(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

चलिए, डैगर को बताते हैं कि बनाने के लिए, बाकी डिपेंडेंसी कैसे दी जाए ग्राफ़:

Kotlin

class UserRepository @Inject constructor(
    private val localDataSource: UserLocalDataSource,
    private val remoteDataSource: UserRemoteDataSource
) { ... }

class UserLocalDataSource @Inject constructor() { ... }
class UserRemoteDataSource @Inject constructor(
    private val loginService: LoginRetrofitService
) { ... }

Java

public class UserRepository {

    private final UserLocalDataSource userLocalDataSource;
    private final UserRemoteDataSource userRemoteDataSource;

    @Inject
    public UserRepository(UserLocalDataSource userLocalDataSource, UserRemoteDataSource userRemoteDataSource) {
        this.userLocalDataSource = userLocalDataSource;
        this.userRemoteDataSource = userRemoteDataSource;
    }
}

public class UserLocalDataSource {

    @Inject
    public UserLocalDataSource() {}
}

public class UserRemoteDataSource {

    private final LoginRetrofitService loginRetrofitService;

    @Inject
    public UserRemoteDataSource(LoginRetrofitService loginRetrofitService) {
        this.loginRetrofitService = loginRetrofitService;
    }
}

डैगर मॉड्यूल

इस उदाहरण के लिए, Retrofit नेटवर्किंग लाइब्रेरी का इस्तेमाल किया जा रहा है. UserRemoteDataSource, LoginRetrofitService पर निर्भर है. हालांकि, LoginRetrofitService का इंस्टेंस बनाने का तरीका, इससे अलग है हैं, तो आपको पता चलेगा. यह क्लास इंस्टैंशिएट नहीं है; यह इस बात का नतीजा है कि कॉन्फ़िगर करने के लिए, Retrofit.Builder() को कॉल करना और अलग-अलग पैरामीटर में पास करना लॉगिन सेवा.

@Inject एनोटेशन के अलावा, डैगर को यह बताने का एक और तरीका है क्लास का एक इंस्टेंस दें: डैगर मॉड्यूल के अंदर की जानकारी. अ डैगर मॉड्यूल एक क्लास है जो @Module के साथ एनोटेट की गई है. वहां जाकर, डिपेंडेंसी के तौर पर @Provides एनोटेशन का इस्तेमाल किया जा सकता है.

Kotlin

// @Module informs Dagger that this class is a Dagger Module
@Module
class NetworkModule {

    // @Provides tell Dagger how to create instances of the type that this function
    // returns (i.e. LoginRetrofitService).
    // Function parameters are the dependencies of this type.
    @Provides
    fun provideLoginRetrofitService(): LoginRetrofitService {
        // Whenever Dagger needs to provide an instance of type LoginRetrofitService,
        // this code (the one inside the @Provides method) is run.
        return Retrofit.Builder()
                .baseUrl("https://example.com")
                .build()
                .create(LoginService::class.java)
    }
}

Java

// @Module informs Dagger that this class is a Dagger Module
@Module
public class NetworkModule {

    // @Provides tell Dagger how to create instances of the type that this function
    // returns (i.e. LoginRetrofitService).
    // Function parameters are the dependencies of this type.
    @Provides
    public LoginRetrofitService provideLoginRetrofitService() {
        // Whenever Dagger needs to provide an instance of type LoginRetrofitService,
        // this code (the one inside the @Provides method) is run.
        return new Retrofit.Builder()
                .baseUrl("https://example.com")
                .build()
                .create(LoginService.class);
    }
}

मॉड्यूल की मदद से, कॉन्टेंट को शब्दों के हिसाब से समझाया जा सकता है. ऑब्जेक्ट हैं. जैसा कि आपको दिख रहा है, लॉजिक के हिसाब से ग्रुप बनाने के लिए, आपने क्लास NetworkModule को कॉल किया है नेटवर्किंग से जुड़ी चीज़ें उपलब्ध कराने के लिए. अगर ऐप्लिकेशन विस्तृत होता है, तो आप यहां OkHttpClient देने का तरीका या Gson या Moshi कॉन्फ़िगर करें.

@Provides तरीके की डिपेंडेंसी, उस तरीके के पैरामीटर हैं. इसके लिए आपने पहले भी कहा है कि LoginRetrofitService किसी डिपेंडेंसी के बिना दिया जा सकता है क्योंकि इस तरीके में कोई पैरामीटर नहीं है. अगर आपने OkHttpClient को पैरामीटर के लिए डैगर कोOkHttpClient ग्राफ़ की मदद से, LoginRetrofitService की डिपेंडेंसी के हिसाब से डेटा दिखाया जाता है. उदाहरण के लिए:

Kotlin

@Module
class NetworkModule {
    // Hypothetical dependency on LoginRetrofitService
    @Provides
    fun provideLoginRetrofitService(
        okHttpClient: OkHttpClient
    ): LoginRetrofitService { ... }
}

Java

@Module
public class NetworkModule {

    @Provides
    public LoginRetrofitService provideLoginRetrofitService(OkHttpClient okHttpClient) {
        ...
    }
}

डैगर ग्राफ़ को इस मॉड्यूल के बारे में जानने के लिए, आपको इसे @Component इंटरफ़ेस इस तरह दिखेगा:

Kotlin

// The "modules" attribute in the @Component annotation tells Dagger what Modules
// to include when building the graph
@Component(modules = [NetworkModule::class])
interface ApplicationComponent {
    ...
}

Java

// The "modules" attribute in the @Component annotation tells Dagger what Modules
// to include when building the graph
@Component(modules = NetworkModule.class)
public interface ApplicationComponent {
    ...
}

डैगर ग्राफ़ में टाइप जोड़ने के लिए, कंस्ट्रक्टर का इस्तेमाल करने का सुझाव दिया जाता है इंजेक्शन (उदाहरण के लिए, क्लास के कंस्ट्रक्टर पर @Inject एनोटेशन के साथ). कभी-कभी, ऐसा करना मुमकिन नहीं होता और आपको डैगर मॉड्यूल का इस्तेमाल करना पड़ता है. एक उदाहरण जब आप चाहते हैं कि डैगर किसी कंप्यूटेशन के नतीजे का इस्तेमाल करके यह तय करें कि किसी ऑब्जेक्ट का इंस्टेंस बनाएं. जब भी इसे उसका कोई इंस्टेंस देना होता है टाइप, डैगर @Provides तरीके के अंदर कोड चलाता है.

फ़िलहाल, इस उदाहरण में डैगर ग्राफ़ कुछ इस तरह दिखता है:

लॉगिन ऐक्टिविटी डिपेंडेंसी ग्राफ़ का डायग्राम

दूसरा डायग्राम. ग्राफ़ को इसके साथ प्रस्तुत करना डैगर, LoginActivity को इंजेक्ट कर रहे हैं

ग्राफ़ का एंट्री पॉइंट LoginActivity है. क्योंकि LoginActivity इंजेक्ट करता है LoginViewModel, डैगर एक ग्राफ़ बनाता है, जिसमें यह जानकारी होती है कि किसी इंस्टेंस को कैसे उपलब्ध कराया जाए का LoginViewModel और बार-बार देखा जा सकता है. डैगर जानता है कि कैसे ऐसा क्लास पर @Inject एनोटेशन की वजह से किया जा सकता है कंस्ट्रक्टर है.

डैगर के जनरेट किए गए ApplicationComponent में, एक फ़ैक्ट्री टाइप की जानकारी मौजूद है का इस्तेमाल करने का सुझाव देता है. इसमें उदाहरण के लिए, डैगर इसमें शामिल NetworkModule को डेलिगेट करते हैं LoginRetrofitService का इंस्टेंस पाने के लिए, ApplicationComponent.

डैगर स्कोप

डैगर की बुनियादी बातें पेज पर उन दायरों के बारे में बताया गया था जिनकी मदद से किसी कॉम्पोनेंट में किसी टाइप का यूनीक इंस्टेंस. इसका मतलब यह है कॉम्पोनेंट के लाइफ़साइकल के हिसाब से टाइप को स्कोप करना.

क्योंकि आप ऐप्लिकेशन की अन्य सुविधाओं में UserRepository का इस्तेमाल कर सकते हैं और हो सकता है कि आप अपनी ज़रूरत के हिसाब से हर बार नया ऑब्जेक्ट न बनाना चाहें, तो आपके पास इसे पूरे ऐप्लिकेशन के लिए एक खास इंस्टेंस के रूप में रखा जाता है. यह इसके लिए समान है LoginRetrofitService: इसे बनाना महंगा हो सकता है और आपको यह भी चाहिए कि का यूनीक इंस्टेंस जिसे फिर से इस्तेमाल किया जा सके. इसका इंस्टेंस बनाना UserRemoteDataSource इतना महंगा नहीं है, इसलिए इसे कॉम्पोनेंट का लाइफ़साइकल ज़रूरी नहीं है.

सिर्फ़ @Singleton दायरे की जानकारी देता है javax.inject पैकेज. ApplicationComponent के बारे में बताने के लिए, इसका इस्तेमाल किया जा सकता है और वे ऑब्जेक्ट जिन्हें पूरे ऐप्लिकेशन में फिर से इस्तेमाल करना है.

Kotlin

@Singleton
@Component(modules = [NetworkModule::class])
interface ApplicationComponent {
    fun inject(activity: LoginActivity)
}

@Singleton
class UserRepository @Inject constructor(
    private val localDataSource: UserLocalDataSource,
    private val remoteDataSource: UserRemoteDataSource
) { ... }

@Module
class NetworkModule {
    // Way to scope types inside a Dagger Module
    @Singleton
    @Provides
    fun provideLoginRetrofitService(): LoginRetrofitService { ... }
}

Java

@Singleton
@Component(modules = NetworkModule.class)
public interface ApplicationComponent {
    void inject(LoginActivity loginActivity);
}

@Singleton
public class UserRepository {

    private final UserLocalDataSource userLocalDataSource;
    private final UserRemoteDataSource userRemoteDataSource;

    @Inject
    public UserRepository(UserLocalDataSource userLocalDataSource, UserRemoteDataSource userRemoteDataSource) {
        this.userLocalDataSource = userLocalDataSource;
        this.userRemoteDataSource = userRemoteDataSource;
    }
}

@Module
public class NetworkModule {

    @Singleton
    @Provides
    public LoginRetrofitService provideLoginRetrofitService() { ... }
}

ऑब्जेक्ट पर स्कोप लागू करते समय, ध्यान रखें कि मेमोरी लीक होने की समस्या न आए. जैसे जब तक स्कोप वाला कॉम्पोनेंट, मेमोरी में मौजूद रहता है, तब तक बनाया गया ऑब्जेक्ट, मेमोरी में मौजूद होता है भी. क्योंकि ApplicationComponent को ऐप्लिकेशन लॉन्च होने पर बनाया जाता है (इसमें Application क्लास), ऐप्लिकेशन के बंद होने पर यह खत्म हो जाता है. इसलिए, UserRepository का यूनीक इंस्टेंस हमेशा मेमोरी में तब तक बना रहता है, जब तक ऐप्लिकेशन को नष्ट कर दिया गया है.

डैगर सबकॉम्पोनेंट

अगर आपके लॉगिन फ़्लो (एक ही LoginActivity से मैनेज किया जाता है) में कई फ़्रैगमेंट, आपको LoginViewModel के उसी इंस्टेंस का फिर से इस्तेमाल करना चाहिए फ़्रैगमेंट. @Singleton, LoginViewModel की व्याख्या नहीं कर सकता, ताकि इंस्टेंस का फिर से इस्तेमाल किया जा सके नीचे दी गई वजहों से:

  1. फ़्लो के बाद LoginViewModel का इंस्टेंस मेमोरी में बना रहेगा खत्म हुआ.

  2. आपको हर लॉगिन फ़्लो के लिए, LoginViewModel का अलग इंस्टेंस चाहिए. उदाहरण के लिए, अगर उपयोगकर्ता लॉग आउट हो जाता है, तो आपको LoginViewModel, उसी इंस्टेंस के बजाय जब उपयोगकर्ता ने लॉग इन किया था पहली बार.

LoginViewModel को LoginActivity के लाइफ़साइकल का स्कोप करने के लिए, आपको बनाना होगा लॉगिन फ़्लो और नए स्कोप के लिए, एक नया कॉम्पोनेंट (एक नया सबग्राफ़).

लॉगिन फ़्लो के हिसाब से एक ग्राफ़ बनाएं.

Kotlin

@Component
interface LoginComponent {}

Java

@Component
public interface LoginComponent {
}

अब, LoginActivity को LoginComponent से इंजेक्शन लेना चाहिए, क्योंकि यह में लॉगिन के लिए खास कॉन्फ़िगरेशन होता है. इससे इंजेक्ट करने की ज़िम्मेदारी खत्म हो जाती है ApplicationComponent क्लास से LoginActivity.

Kotlin

@Component
interface LoginComponent {
    fun inject(activity: LoginActivity)
}

Java

@Component
public interface LoginComponent {
    void inject(LoginActivity loginActivity);
}

LoginComponent के पास, ApplicationComponent के ऑब्जेक्ट ऐक्सेस करने की अनुमति होनी चाहिए क्योंकि LoginViewModel UserRepository पर निर्भर है. डैगर को यह बताने का तरीका कि आपकी इच्छा है कि नया कॉम्पोनेंट, किसी दूसरे कॉम्पोनेंट का हिस्सा इस्तेमाल करे, डैगर सबकॉम्पोनेंट. नया कॉम्पोनेंट, घटक में शामिल है.

सबकॉम्पोनेंट ऐसे कॉम्पोनेंट होते हैं जो किसी पैरंट कॉम्पोनेंट. इसलिए, पैरंट कॉम्पोनेंट में दिए गए सभी ऑब्जेक्ट, सबकॉम्पोनेंट में भी दी जाती है. इस तरह, सबकॉम्पोनेंट से कोई ऑब्जेक्ट यह पैरंट कॉम्पोनेंट से मिले ऑब्जेक्ट के हिसाब से हो सकता है.

सबकॉम्पोनेंट के इंस्टेंस बनाने के लिए, आपके पास पैरंट का एक इंस्टेंस होना चाहिए कॉम्पोनेंट. इसलिए, पैरंट कॉम्पोनेंट से सबकॉम्पोनेंट अब भी पैरंट कॉम्पोनेंट तक ही सीमित है.

इस उदाहरण में, आपको LoginComponent को इसके सबकॉम्पोनेंट के रूप में परिभाषित करना होगा ApplicationComponent. ऐसा करने के लिए, LoginComponent पर इसके साथ एनोटेट करें: @Subcomponent:

Kotlin

// @Subcomponent annotation informs Dagger this interface is a Dagger Subcomponent
@Subcomponent
interface LoginComponent {

    // This tells Dagger that LoginActivity requests injection from LoginComponent
    // so that this subcomponent graph needs to satisfy all the dependencies of the
    // fields that LoginActivity is injecting
    fun inject(loginActivity: LoginActivity)
}

Java

// @Subcomponent annotation informs Dagger this interface is a Dagger Subcomponent
@Subcomponent
public interface LoginComponent {

    // This tells Dagger that LoginActivity requests injection from LoginComponent
    // so that this subcomponent graph needs to satisfy all the dependencies of the
    // fields that LoginActivity is injecting
    void inject(LoginActivity loginActivity);
}

आपको LoginComponent में सबकॉम्पोनेंट फ़ैक्ट्री भी तय करना होगा, ताकि ApplicationComponent को LoginComponent के इंस्टेंस बनाने का तरीका पता है.

Kotlin

@Subcomponent
interface LoginComponent {

    // Factory that is used to create instances of this subcomponent
    @Subcomponent.Factory
    interface Factory {
        fun create(): LoginComponent
    }

    fun inject(loginActivity: LoginActivity)
}

Java

@Subcomponent
public interface LoginComponent {

    // Factory that is used to create instances of this subcomponent
    @Subcomponent.Factory
    interface Factory {
        LoginComponent create();
    }

    void inject(LoginActivity loginActivity);
}

डैगर को यह बताने के लिए कि LoginComponent एक सबकॉम्पोनेंट है ApplicationComponent, आपको इसे इस तरीके से बताना होगा:

  1. पासिंग पास करने के लिए एक नया डैगर मॉड्यूल बनाना (जैसे SubcomponentsModule) सबकॉम्पोनेंट की क्लास को एनोटेशन के subcomponents एट्रिब्यूट में जोड़ा जाता है.

    Kotlin

    // The "subcomponents" attribute in the @Module annotation tells Dagger what
    // Subcomponents are children of the Component this module is included in.
    @Module(subcomponents = LoginComponent::class)
    class SubcomponentsModule {}
    

    Java

    // The "subcomponents" attribute in the @Module annotation tells Dagger what
    // Subcomponents are children of the Component this module is included in.
    @Module(subcomponents = LoginComponent.class)
    public class SubcomponentsModule {
    }
    
  2. ApplicationComponent में नया मॉड्यूल (यानी SubcomponentsModule) जोड़ना:

    Kotlin

    // Including SubcomponentsModule, tell ApplicationComponent that
    // LoginComponent is its subcomponent.
    @Singleton
    @Component(modules = [NetworkModule::class, SubcomponentsModule::class])
    interface ApplicationComponent {
    }
    

    Java

    // Including SubcomponentsModule, tell ApplicationComponent that
    // LoginComponent is its subcomponent.
    @Singleton
    @Component(modules = {NetworkModule.class, SubcomponentsModule.class})
    public interface ApplicationComponent {
    }
    

    ध्यान दें कि ApplicationComponent को अब LoginActivity इंजेक्ट करने की ज़रूरत नहीं है क्योंकि अब यह ज़िम्मेदारी LoginComponent की है, इसलिए आप ApplicationComponent से, inject() तरीका.

    ApplicationComponent के उपभोक्ताओं को यह जानना ज़रूरी है कि इंस्टेंस कैसे बनाए जाते हैं LoginComponent. पैरंट कॉम्पोनेंट को इसके इंटरफ़ेस में एक तरीका जोड़ना होगा, ताकि उपभोक्ता, सबकॉम्पोनेंट के इंस्टेंस बनाते हैं. पैरंट कॉम्पोनेंट:

  3. उस फ़ैक्ट्री को सार्वजनिक करें जो डेटा के मामले में LoginComponent इंटरफ़ेस:

    Kotlin

    @Singleton
    @Component(modules = [NetworkModule::class, SubcomponentsModule::class])
    interface ApplicationComponent {
    // This function exposes the LoginComponent Factory out of the graph so consumers
    // can use it to obtain new instances of LoginComponent
    fun loginComponent(): LoginComponent.Factory
    }
    

    Java

    @Singleton
    @Component(modules = { NetworkModule.class, SubcomponentsModule.class} )
    public interface ApplicationComponent {
    // This function exposes the LoginComponent Factory out of the graph so consumers
    // can use it to obtain new instances of LoginComponent
    LoginComponent.Factory loginComponent();
    }
    

सबकॉम्पोनेंट के लिए स्कोप असाइन करना

अगर प्रोजेक्ट बनाया जाता है, तो ApplicationComponent दोनों के इंस्टेंस बनाए जा सकते हैं और LoginComponent. ApplicationComponent इसकी लाइफ़साइकल से जुड़ा है क्योंकि आप ग्राफ़ के समान इंस्टेंस का तब तक उपयोग करना चाहते हैं, जब तक ऐप्लिकेशन मेमोरी में हो.

LoginComponent का लाइफ़साइकल क्या है? आपको किन वजहों से LoginComponent इसलिए है, क्योंकि आपको लॉगिन से जुड़े अलग-अलग हिस्सों के बीच LoginViewModel. हालांकि, आप यह भी चाहते हैं कि नया लॉगिन फ़्लो होने पर, LoginViewModel के इंस्टेंस. LoginActivity अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है LoginComponent के लिए यह सही लाइफ़टाइम है: हर नई गतिविधि के लिए आपको इनकी ज़रूरत होगी LoginComponent और फ़्रैगमेंट का एक नया इंस्टेंस जो LoginComponent.

LoginComponent, LoginActivity के लाइफ़साइकल से जुड़ा है. इसलिए, आपको यह करना होगा गतिविधि में कॉम्पोनेंट का रेफ़रंस उसी तरह रखें जिस तरह आपने Application क्लास में applicationComponent का रेफ़रंस. इस तरह, फ़्रैगमेंट इसे ऐक्सेस कर सकते हैं.

Kotlin

class LoginActivity: Activity() {
    // Reference to the Login graph
    lateinit var loginComponent: LoginComponent
    ...
}

Java

public class LoginActivity extends Activity {

    // Reference to the Login graph
    LoginComponent loginComponent;

    ...
}

ध्यान दें कि वैरिएबल loginComponent के साथ @Inject के बारे में जानकारी नहीं दी गई है क्योंकि आप डैगर से वह वैरिएबल देने की उम्मीद नहीं कर रहे हैं.

LoginComponent का रेफ़रंस पाने के लिए, ApplicationComponent का इस्तेमाल किया जा सकता है और फिर LoginActivity को इस तरह इंजेक्ट करें:

Kotlin

class LoginActivity: Activity() {
    // Reference to the Login graph
    lateinit var loginComponent: LoginComponent

    // Fields that need to be injected by the login graph
    @Inject lateinit var loginViewModel: LoginViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        // Creation of the login graph using the application graph
        loginComponent = (applicationContext as MyDaggerApplication)
                            .appComponent.loginComponent().create()

        // Make Dagger instantiate @Inject fields in LoginActivity
        loginComponent.inject(this)

        // Now loginViewModel is available

        super.onCreate(savedInstanceState)
    }
}

Java

public class LoginActivity extends Activity {

    // Reference to the Login graph
    LoginComponent loginComponent;

    // Fields that need to be injected by the login graph
    @Inject
    LoginViewModel loginViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // Creation of the login graph using the application graph
        loginComponent = ((MyApplication) getApplicationContext())
                                .appComponent.loginComponent().create();

        // Make Dagger instantiate @Inject fields in LoginActivity
        loginComponent.inject(this);

        // Now loginViewModel is available

        super.onCreate(savedInstanceState);
    }
}

LoginComponent को गतिविधि की onCreate() तरीके में बनाया गया है और यह गतिविधि खत्म होने पर उसे आसानी से खत्म कर दिया जाता है.

LoginComponent में हमेशा LoginViewModel का ही इंस्टेंस देना ज़रूरी है हर बार फिर से भेजने का अनुरोध करती है. कस्टम एनोटेशन बनाकर यह पक्का किया जा सकता है और इसके साथ LoginComponent और LoginViewModel, दोनों को एनोटेट करके एनोटेट किया हुआ है. नोट जोड़ें कि आप @Singleton एनोटेशन का इस्तेमाल नहीं कर सकते, क्योंकि इसे पहले ही इस्तेमाल किया जा चुका है और इससे ऑब्जेक्ट, ऐप्लिकेशन सिंगलटन बन जाएगा (पूरे ऐप्लिकेशन के लिए यूनीक इंस्टेंस). आपको एक अलग एनोटेशन बनाना होगा दायरा.

इस मामले में, आप इस दायरे को @LoginScope कह सकते हैं, लेकिन यह अच्छा नहीं है करते हैं. दायरे की जानकारी का नाम, मकसद के बारे में साफ़ तौर पर नहीं बताना चाहिए पूरा करता है. इसके बजाय, इसे लाइफ़टाइम के आधार पर नाम दिया जाना चाहिए, क्योंकि एनोटेशन को सिबलिंग कॉम्पोनेंट, जैसे कि RegistrationComponent के ज़रिए फिर से इस्तेमाल किया जा सकता है और SettingsComponent. इसलिए, आपको इसे @ActivityScope नाम देना चाहिए कुल @LoginScope.

Kotlin

// Definition of a custom scope called ActivityScope
@Scope
@Retention(value = AnnotationRetention.RUNTIME)
annotation class ActivityScope

// Classes annotated with @ActivityScope are scoped to the graph and the same
// instance of that type is provided every time the type is requested.
@ActivityScope
@Subcomponent
interface LoginComponent { ... }

// A unique instance of LoginViewModel is provided in Components
// annotated with @ActivityScope
@ActivityScope
class LoginViewModel @Inject constructor(
    private val userRepository: UserRepository
) { ... }

Java

// Definition of a custom scope called ActivityScope
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {}

// Classes annotated with @ActivityScope are scoped to the graph and the same
// instance of that type is provided every time the type is requested.
@ActivityScope
@Subcomponent
public interface LoginComponent { ... }

// A unique instance of LoginViewModel is provided in Components
// annotated with @ActivityScope
@ActivityScope
public class LoginViewModel {

    private final UserRepository userRepository;

    @Inject
    public LoginViewModel(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

अब, अगर आपके पास ऐसे दो फ़्रैगमेंट थे जिनके लिए LoginViewModel की ज़रूरत थी, तो दोनों फ़्रैगमेंट समान इंस्टेंस के साथ दिया गया है. उदाहरण के लिए, अगर आपके पास LoginUsernameFragment और LoginPasswordFragment को इंजेक्ट करना होगा LoginComponent के ज़रिए:

Kotlin

@ActivityScope
@Subcomponent
interface LoginComponent {

    @Subcomponent.Factory
    interface Factory {
        fun create(): LoginComponent
    }

    // All LoginActivity, LoginUsernameFragment and LoginPasswordFragment
    // request injection from LoginComponent. The graph needs to satisfy
    // all the dependencies of the fields those classes are injecting
    fun inject(loginActivity: LoginActivity)
    fun inject(usernameFragment: LoginUsernameFragment)
    fun inject(passwordFragment: LoginPasswordFragment)
}

Java

@ActivityScope
@Subcomponent
public interface LoginComponent {

    @Subcomponent.Factory
    interface Factory {
        LoginComponent create();
    }

    // All LoginActivity, LoginUsernameFragment and LoginPasswordFragment
    // request injection from LoginComponent. The graph needs to satisfy
    // all the dependencies of the fields those classes are injecting
    void inject(LoginActivity loginActivity);
    void inject(LoginUsernameFragment loginUsernameFragment);
    void inject(LoginPasswordFragment loginPasswordFragment);
}

कॉम्पोनेंट, इसमें मौजूद कॉम्पोनेंट के इंस्टेंस को ऐक्सेस करते हैं LoginActivity ऑब्जेक्ट. LoginUserNameFragment के लिए कोड का उदाहरण कोड स्निपेट पर जाएं:

Kotlin

class LoginUsernameFragment: Fragment() {

    // Fields that need to be injected by the login graph
    @Inject lateinit var loginViewModel: LoginViewModel

    override fun onAttach(context: Context) {
        super.onAttach(context)

        // Obtaining the login graph from LoginActivity and instantiate
        // the @Inject fields with objects from the graph
        (activity as LoginActivity).loginComponent.inject(this)

        // Now you can access loginViewModel here and onCreateView too
        // (shared instance with the Activity and the other Fragment)
    }
}

Java

public class LoginUsernameFragment extends Fragment {

    // Fields that need to be injected by the login graph
    @Inject
    LoginViewModel loginViewModel;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        // Obtaining the login graph from LoginActivity and instantiate
        // the @Inject fields with objects from the graph
        ((LoginActivity) getActivity()).loginComponent.inject(this);

        // Now you can access loginViewModel here and onCreateView too
        // (shared instance with the Activity and the other Fragment)
    }
}

LoginPasswordFragment के लिए भी ऐसा ही है:

Kotlin

class LoginPasswordFragment: Fragment() {

    // Fields that need to be injected by the login graph
    @Inject lateinit var loginViewModel: LoginViewModel

    override fun onAttach(context: Context) {
        super.onAttach(context)

        (activity as LoginActivity).loginComponent.inject(this)

        // Now you can access loginViewModel here and onCreateView too
        // (shared instance with the Activity and the other Fragment)
    }
}

Java

public class LoginPasswordFragment extends Fragment {

    // Fields that need to be injected by the login graph
    @Inject
    LoginViewModel loginViewModel;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        ((LoginActivity) getActivity()).loginComponent.inject(this);

        // Now you can access loginViewModel here and onCreateView too
        // (shared instance with the Activity and the other Fragment)
    }
}

इमेज 3 में दिखाया गया है कि डैगर ग्राफ़, नए सबकॉम्पोनेंट के साथ कैसा दिखता है. क्लास सफ़ेद बिंदु (UserRepository, LoginRetrofitService, और LoginViewModel) के साथ ऐसे मामले होते हैं जिनका एक यूनीक इंस्टेंस होता है.

आखिरी सबकॉम्पोनेंट को जोड़ने के बाद, ऐप्लिकेशन ग्राफ़

तीसरी इमेज. आपके बनाए गए ग्राफ़ का प्रतिनिधित्व Android ऐप्लिकेशन वाले उदाहरण के लिए

आइए, ग्राफ़ के अलग-अलग हिस्सों को देखें:

  1. NetworkModule (इसलिए, LoginRetrofitService) शामिल है ApplicationComponent में, क्योंकि आपने इसे कॉम्पोनेंट में बताया था.

  2. UserRepository ApplicationComponent में मौजूद है, क्योंकि इसका दायरा ApplicationComponent. अगर प्रोजेक्ट में बढ़ोतरी होती है, तो आपको उससे जुड़ा कॉन्टेंट भी शेयर करना चाहिए इंस्टेंस अलग-अलग सुविधाओं (जैसे रजिस्ट्रेशन) के लिए.

    UserRepository, ApplicationComponent का हिस्सा है, इसलिए इसकी डिपेंडेंसी (यानी UserLocalDataSource और UserRemoteDataSource) इसमें होना ज़रूरी है कॉम्पोनेंट को भी अनुमति देनी होगी, ताकि UserRepository के इंस्टेंस दिए जा सकें.

  3. LoginViewModel को LoginComponent में शामिल किया गया है, क्योंकि यह सिर्फ़ ज़रूरी है LoginComponent की ओर से इंजेक्ट की गई क्लास से मिले. LoginViewModel इसमें शामिल नहीं है ApplicationComponent क्योंकि ApplicationComponent पर कोई डिपेंडेंसी नहीं है LoginViewModel.

    इसी तरह, अगर आपने UserRepository से ApplicationComponent तक का दायरा नहीं बनाया होता, डैगर, UserRepository और उसकी डिपेंडेंसी को अपने-आप शामिल कर लेगा LoginComponent के हिस्से के रूप में क्योंकि वर्तमान में केवल यही एक स्थान है UserRepository का इस्तेमाल किया गया है.

ऑब्जेक्ट को अलग-अलग लाइफ़साइकल में स्कोप करने के अलावा, सबकॉम्पोनेंट बनाने के लिए यह आपके आवेदन के अलग-अलग हिस्सों को इनकैप्सुलेट करने का एक अच्छा तरीका है एक-दूसरे से जुड़ी हुई क्वेरी हैं.

फ़्लो के हिसाब से, अलग-अलग डैगर सबग्राफ़ बनाने के लिए अपने ऐप्लिकेशन का स्ट्रक्चर तैयार करना आपके ऐप्लिकेशन को ज़्यादा बेहतर और बढ़ाने लायक ऐप्लिकेशन बनाने में मदद मिलती है. की मेमोरी और स्टार्टअप समय की शर्तें होती हैं.

डैगर ग्राफ़ बनाने के सबसे सही तरीके

अपने ऐप्लिकेशन के लिए डैगर ग्राफ़ बनाते समय:

  • कॉम्पोनेंट बनाते समय, आपको देखना चाहिए कि कौनसा एलिमेंट इसके लिए ज़िम्मेदार है वैल्यू को हमेशा के लिए मिटा दिया जाता है. इस मामले में, Application क्लास इसमें है ApplicationComponent और LoginActivity का प्रभारी LoginComponent.

  • स्कोपिंग का इस्तेमाल सिर्फ़ तब करें, जब यह सही हो. सीमा का ज़्यादा इस्तेमाल करने पर नकारात्मकता हो सकती है इसका असर आपके ऐप्लिकेशन के रनटाइम की परफ़ॉर्मेंस पर पड़ता है: ऑब्जेक्ट तब तक मेमोरी में रहता है, जब तक ऐसा इसलिए होता है, क्योंकि कॉम्पोनेंट मेमोरी में होता है. इसलिए, स्कोप वाला ऑब्जेक्ट पाने में ज़्यादा खर्च आता है. जब डैगर ऑब्जेक्ट मुहैया कराता है, तो वहDoubleCheck फ़ैक्ट्री टाइप की सेवा देने वाली कंपनी.

डैगर का इस्तेमाल करने वाले प्रोजेक्ट का टेस्ट करना

डैगर जैसे डिपेंडेंसी इंजेक्शन फ़्रेमवर्क का इस्तेमाल करने का एक फ़ायदा यह है कि इससे आपके कोड की जांच करना आसान हो जाता है.

यूनिट टेस्ट

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

उदाहरण के लिए, LoginViewModel की जांच करते समय:

Kotlin

@ActivityScope
class LoginViewModel @Inject constructor(
    private val userRepository: UserRepository
) { ... }

class LoginViewModelTest {

    @Test
    fun `Happy path`() {
        // You don't need Dagger to create an instance of LoginViewModel
        // You can pass a fake or mock UserRepository
        val viewModel = LoginViewModel(fakeUserRepository)
        assertEquals(...)
    }
}

Java

@ActivityScope
public class LoginViewModel {

    private final UserRepository userRepository;

    @Inject
    public LoginViewModel(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

public class LoginViewModelTest {

    @Test
    public void happyPath() {
        // You don't need Dagger to create an instance of LoginViewModel
        // You can pass a fake or mock UserRepository
        LoginViewModel viewModel = new LoginViewModel(fakeUserRepository);
        assertEquals(...);
    }
}

शुरू से अंत तक के टेस्ट

इंटिग्रेशन टेस्ट के लिए, एक अच्छा तरीका TestApplicationComponent को टेस्ट करने के लिए बनाया गया है. प्रोडक्शन और टेस्टिंग, कॉम्पोनेंट के अलग-अलग कॉन्फ़िगरेशन का इस्तेमाल करते हैं.

इसके लिए ज़्यादा अप-फ़्रंट मॉड्यूल के डिज़ाइन की ज़रूरत होती है आपका ऐप्लिकेशन. टेस्टिंग कॉम्पोनेंट, प्रोडक्शन कॉम्पोनेंट को बढ़ाता है और मॉड्यूल का एक अलग सेट इंस्टॉल करता है.

Kotlin

// TestApplicationComponent extends from ApplicationComponent to have them both
// with the same interface methods. You need to include the modules of the
// component here as well, and you can replace the ones you want to override.
// This sample uses FakeNetworkModule instead of NetworkModule
@Singleton
@Component(modules = [FakeNetworkModule::class, SubcomponentsModule::class])
interface TestApplicationComponent : ApplicationComponent {
}

Java

// TestApplicationComponent extends from ApplicationComponent to have them both
// with the same interface methods. You need to include the modules of the
// Component here as well, and you can replace the ones you want to override.
// This sample uses FakeNetworkModule instead of NetworkModule
@Singleton
@Component(modules = {FakeNetworkModule.class, SubcomponentsModule.class})
public interface TestApplicationComponent extends ApplicationComponent {
}

FakeNetworkModule में मूल NetworkModule को नकली तरीके से लागू किया गया है. यहां उस कॉन्टेंट के नकली इंस्टेंस या मॉक उपलब्ध कराए जा सकते हैं, जिसकी जगह आपको इस्तेमाल करना है.

Kotlin

// In the FakeNetworkModule, pass a fake implementation of LoginRetrofitService
// that you can use in your tests.
@Module
class FakeNetworkModule {
    @Provides
    fun provideLoginRetrofitService(): LoginRetrofitService {
        return FakeLoginService()
    }
}

Java

// In the FakeNetworkModule, pass a fake implementation of LoginRetrofitService
// that you can use in your tests.
@Module
public class FakeNetworkModule {

    @Provides
    public LoginRetrofitService provideLoginRetrofitService() {
        return new FakeLoginService();
    }
}

अपने इंटिग्रेशन या एंड-टू-एंड टेस्ट में, आप ऐसे TestApplication का इस्तेमाल करेंगे जो यह ApplicationComponent के बजाय TestApplicationComponent को बनाता है.

Kotlin

// Your test application needs an instance of the test graph
class MyTestApplication: MyApplication() {
    override val appComponent = DaggerTestApplicationComponent.create()
}

Java

// Your test application needs an instance of the test graph
public class MyTestApplication extends MyApplication {
    ApplicationComponent appComponent = DaggerTestApplicationComponent.create();
}

इसके बाद, इस टेस्ट ऐप्लिकेशन का इस्तेमाल पसंद के मुताबिक बनाए गए TestRunner में किया जाता है, ताकि आप इंस्ट्रुमेंटेशन टेस्ट चलाना. इस बारे में अधिक जानकारी के लिए, यह देखें Android ऐप्लिकेशन के कोडलैब में डैगर का इस्तेमाल करें.

डैगर मॉड्यूल के साथ काम करना

डैगर मॉड्यूल की मदद से, सिमैंटिक तरीके से ऑब्जेक्ट उपलब्ध कराने का तरीका बताया जा सकता है तरीका है. कॉम्पोनेंट में मॉड्यूल शामिल किए जा सकते हैं, लेकिन मॉड्यूल भी शामिल किए जा सकते हैं अन्य मॉड्यूल में इस्तेमाल कर सकते हैं. यह बेहद असरदार है, लेकिन इसका आसानी से गलत इस्तेमाल किया जा सकता है.

एक बार किसी मॉड्यूल को किसी घटक या किसी अन्य मॉड्यूल में जोड़ दिए जाने पर, वह डैगर ग्राफ़ में पहले से मौजूद हैं; डैगर उस कॉम्पोनेंट में वे ऑब्जेक्ट दे सकते हैं. कोई मॉड्यूल जोड़ने से पहले, जांच लें कि वह मॉड्यूल पहले से ही डैगर ग्राफ़ का हिस्सा है या नहीं यह देखने के लिए कि यह कॉम्पोनेंट में पहले से जुड़ा है या प्रोजेक्ट कंपाइल करके और यह देखना कि डैगर उस मॉड्यूल के लिए ज़रूरी डिपेंडेंसी ढूंढ सकता है या नहीं.

अच्छे तरीके से यह बताया जाता है कि किसी कॉम्पोनेंट में मॉड्यूल का एलान सिर्फ़ एक बार किया जाना चाहिए (बेहतर डैगर इस्तेमाल करने के तरीकों के अलावा, अन्य उदाहरण भी जोड़े जा सकते हैं).

मान लें कि आपने अपना ग्राफ़ इस तरह कॉन्फ़िगर किया है. ApplicationComponent अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है Module1 और Module2 शामिल हैं और Module1 में ModuleX शामिल है.

Kotlin

@Component(modules = [Module1::class, Module2::class])
interface ApplicationComponent { ... }

@Module(includes = [ModuleX::class])
class Module1 { ... }

@Module
class Module2 { ... }

Java

@Component(modules = {Module1.class, Module2.class})
public interface ApplicationComponent { ... }

@Module(includes = {ModuleX.class})
public class Module1 { ... }

@Module
public class Module2 { ... }

अगर अभी Module2, ModuleX की क्लास पर निर्भर करता है. गलत तरीका Module2 में ModuleX को शामिल कर रहा है, क्योंकि ModuleX को इसमें दो बार शामिल किया गया है ग्राफ़, जैसा कि नीचे दिए गए कोड स्निपेट में दिखाया गया है:

Kotlin

// Bad practice: ModuleX is declared multiple times in this Dagger graph
@Component(modules = [Module1::class, Module2::class])
interface ApplicationComponent { ... }

@Module(includes = [ModuleX::class])
class Module1 { ... }

@Module(includes = [ModuleX::class])
class Module2 { ... }

Java

// Bad practice: ModuleX is declared multiple times in this Dagger graph.
@Component(modules = {Module1.class, Module2.class})
public interface ApplicationComponent { ... }

@Module(includes = ModuleX.class)
public class Module1 { ... }

@Module(includes = ModuleX.class)
public class Module2 { ... }

इसके बजाय, आपको इनमें से कोई एक काम करना चाहिए:

  1. मॉड्यूल को रीफ़ैक्टर करके, सामान्य मॉड्यूल को कॉम्पोनेंट.
  2. ऐसे ऑब्जेक्ट के साथ एक नया मॉड्यूल बनाएं जिन्हें मॉड्यूल शेयर और एक्सट्रैक्ट करते हैं उसे कॉम्पोनेंट तक पहुंचाता है.

इस तरह से रीफ़ैक्टर न करने पर, एक-दूसरे के साथ-साथ कई मॉड्यूल बन जाते हैं संगठन की जानकारी के बिना और यह देखना और भी मुश्किल हो जाता है कि हर डिपेंडेंसी से आ रही है.

अच्छा तरीका (पहला विकल्प): डैगर ग्राफ़ में, ModuleX का एलान एक बार किया गया है.

Kotlin

@Component(modules = [Module1::class, Module2::class, ModuleX::class])
interface ApplicationComponent { ... }

@Module
class Module1 { ... }

@Module
class Module2 { ... }

Java

@Component(modules = {Module1.class, Module2.class, ModuleX.class})
public interface ApplicationComponent { ... }

@Module
public class Module1 { ... }

@Module
public class Module2 { ... }

अच्छा तरीका (दूसरा विकल्प): Module1 और Module2 की सामान्य डिपेंडेंसी ModuleX में मौजूद एक नए मॉड्यूल में एक्सट्रैक्ट किया जाता है, जिसका नाम ModuleXCommon होता है. कॉम्पोनेंट में शामिल किया गया है. इसके बाद, दो अन्य मॉड्यूल के नाम ModuleXWithModule1Dependencies और ModuleXWithModule2Dependencies को हर मॉड्यूल के लिए खास डिपेंडेंसी के साथ बनाया जाता है. सभी मॉड्यूल डैगर ग्राफ़ में एक बार दर्ज किए जाते हैं.

Kotlin

@Component(modules = [Module1::class, Module2::class, ModuleXCommon::class])
interface ApplicationComponent { ... }

@Module
class ModuleXCommon { ... }

@Module
class ModuleXWithModule1SpecificDependencies { ... }

@Module
class ModuleXWithModule2SpecificDependencies { ... }

@Module(includes = [ModuleXWithModule1SpecificDependencies::class])
class Module1 { ... }

@Module(includes = [ModuleXWithModule2SpecificDependencies::class])
class Module2 { ... }

Java

@Component(modules = {Module1.class, Module2.class, ModuleXCommon.class})
public interface ApplicationComponent { ... }

@Module
public class ModuleXCommon { ... }

@Module
public class ModuleXWithModule1SpecificDependencies { ... }

@Module
public class ModuleXWithModule2SpecificDependencies { ... }

@Module(includes = ModuleXWithModule1SpecificDependencies.class)
public class Module1 { ... }

@Module(includes = ModuleXWithModule2SpecificDependencies.class)
public class Module2 { ... }

इंजेक्शन में मदद की सुविधा

असिस्टेड इंजेक्शन एक डीआई पैटर्न है, जिसका इस्तेमाल एक ऑब्जेक्ट को बनाने के लिए किया जाता है, जहां कुछ पैरामीटर, डीआई फ़्रेमवर्क से उपलब्ध कराए जा सकते हैं और अन्य पैरामीटर को पास करना ज़रूरी होता है बनाते समय इस्तेमाल किया जा सकता है.

Android में, यह पैटर्न विवरण स्क्रीन में सामान्य होता है, जहां की आईडी दिखाने के लिए तत्व केवल रनटाइम के दौरान ज्ञात होता है, न कि कंपाइल करते समय जब डैगर डीआई ग्राफ़ जनरेट करता है. डैगर से असिस्टेड इंजेक्शन के बारे में ज़्यादा जानने के लिए, डैगर का दस्तावेज़ पढ़ें.

नतीजा

अगर आपने अब तक यह सेक्शन नहीं देखा है, तो सबसे सही तरीके वाला सेक्शन देखें. यहां की यात्रा पर हूं यह जानने के लिए कि किसी Android ऐप्लिकेशन में डैगर का इस्तेमाल कैसे किया जाता है, किसी Android ऐप्लिकेशन में डैगर का इस्तेमाल करना कोडलैब (कोड बनाना सीखना).