एक से ज़्यादा Gradle मॉड्यूल वाले प्रोजेक्ट को मल्टी-मॉड्यूल प्रोजेक्ट कहा जाता है.
यह ऐसे मल्टी-मॉड्यूल प्रोजेक्ट में है जो बिना किसी सुविधा के एक APK के तौर पर भेजा जाता है
मॉड्यूल का इस्तेमाल करते हैं, तो आम तौर पर एक app
मॉड्यूल होता है, जो ज़्यादातर मॉड्यूल पर निर्भर करता है
मॉड्यूल और base
या core
मॉड्यूल को इकट्ठा करना बाकी है,
मॉड्यूल आम तौर पर इन पर निर्भर करते हैं. app
मॉड्यूल में आम तौर पर, आपके
Application
क्लास, जबकि base
मॉड्यूल में आपके प्रोजेक्ट के सभी मॉड्यूल में शेयर की जाने वाली सभी सामान्य क्लास शामिल होती हैं.
ऐप्लिकेशन कॉम्पोनेंट के बारे में बताने के लिए, app
मॉड्यूल अच्छी जगह है (इसके लिए
उदाहरण के लिए, नीचे दी गई इमेज में ApplicationComponent
) से ऑब्जेक्ट मिल सकते हैं
दूसरे कॉम्पोनेंट के साथ-साथ आपके ऐप्लिकेशन के सिंगलटन की भी ज़रूरत पड़ सकती है. इस तौर पर
उदाहरण के लिए, OkHttpClient
, JSON पार्सर, आपके डेटाबेस के लिए ऐक्सेसर,
या SharedPreferences
ऑब्जेक्ट जिन्हें core
मॉड्यूल में तय किया जा सकता है,
app
मॉड्यूल में बताए गए ApplicationComponent
से मिलेगी.
app
मॉड्यूल में, आपके पास ऐसे दूसरे कॉम्पोनेंट भी हो सकते हैं जो कम समय तक चलते हैं.
इसका एक उदाहरण उपयोगकर्ता के खास कॉन्फ़िगरेशन वाला UserComponent
हो सकता है
(जैसे कि UserSession
) को लॉग इन करने के बाद.
अपने प्रोजेक्ट के अलग-अलग मॉड्यूल में, कम से कम एक मॉड्यूल तय किया जा सकता है वह सबकॉम्पोनेंट जिसमें उस मॉड्यूल के लिए खास लॉजिक होता है, जैसा कि पहली इमेज में दिखाया गया है.
उदाहरण के लिए, login
मॉड्यूल में, आपके पास LoginComponent
हो सकता है
के दायरे में, पसंद के मुताबिक @ModuleScope
के एनोटेशन हैं, जो समान ऑब्जेक्ट मुहैया करा सकते हैं
उस सुविधा से जुड़ जाना चाहिए, जैसे कि LoginRepository
. उस मॉड्यूल के अंदर, ये काम भी किए जा सकते हैं
ऐसे दूसरे कॉम्पोनेंट होते हैं जो एक अलग कस्टम वाले LoginComponent
पर निर्भर होते हैं
स्कोप, उदाहरण के लिए @FeatureScope
के लिए LoginActivityComponent
या a
TermsAndConditionsComponent
जहां ज़्यादा सुविधा वाले लॉजिक का इस्तेमाल किया जा सकता है
जैसे कि ViewModel
ऑब्जेक्ट.
Registration
जैसे दूसरे मॉड्यूल के लिए, आपके पास मिलता-जुलता सेटअप होगा.
मल्टी-मॉड्यूल प्रोजेक्ट के लिए एक सामान्य नियम यह है कि एक जैसे लेवल के मॉड्यूल एक-दूसरे पर निर्भर नहीं होना चाहिए. अगर वे सहमत हैं, तो देखें कि क्या (उनके बीच की डिपेंडेंसी), पैरंट मॉड्यूल का हिस्सा होनी चाहिए. अगर ऐसा है, तो क्लास को पैरंट मॉड्यूल में ले जाने के लिए रीफ़ैक्टर करें; अगर नहीं है, तो नया मॉड्यूल बनाएं जो पैरंट मॉड्यूल को बड़ा करता है और दोनों ओरिजनल मॉड्यूल में नया मॉड्यूल.
सबसे सही तरीका यह है कि आम तौर पर, मॉड्यूल को नीचे दिए गए मामलों में देखें:
आपको फ़ील्ड इंजेक्शन डालना होगा, जैसा कि
LoginActivityComponent
के साथ किया जाता है.आपको ऑब्जेक्ट का स्कोप करना होगा, जैसा
LoginComponent
के साथ किया जाता है.
अगर इनमें से कोई भी वजह लागू नहीं होती है और आपको डैगर को यह बताना है कि
उस मॉड्यूल से ऑब्जेक्ट इकट्ठा करने के लिए, @Provides
की मदद से डैगर मॉड्यूल बनाएं और उसे सार्वजनिक करें या
@Binds
तरीकों से, अगर इन क्लास में कंस्ट्रक्शन इंजेक्शन नहीं बनाया जा सकता.
डैगर सबकॉम्पोनेंट के साथ लागू करना
Android ऐप्लिकेशन में डैगर का इस्तेमाल करना दस्तावेज़ पेज पर, दस्तावेज़ बनाने और उन्हें इस्तेमाल करने का तरीका बताया गया है
सबकॉम्पोनेंट. हालांकि, आप उसी कोड का उपयोग नहीं कर सकते, क्योंकि
सुविधा वाले मॉड्यूल को app
मॉड्यूल के बारे में जानकारी नहीं है. उदाहरण के लिए, अगर आपको लगता है कि
के सामान्य लॉगिन प्रवाह और पिछले पेज में हमारे कोड के बारे में है, तो यह
और ज़्यादा कंपाइल करें:
Kotlin
class LoginActivity: Activity() { ... 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) ... } }
Java
public class LoginActivity extends Activity { ... @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); ... } }
इसकी वजह यह है कि login
मॉड्यूल को MyApplication
के बारे में जानकारी नहीं है और न ही
appComponent
. इसके काम करने के लिए, आपको इस सुविधा में एक इंटरफ़ेस तय करना होगा
मॉड्यूल जो MyApplication
की ज़रूरत के मुताबिक FeatureComponent
देता है
.
नीचे दिए गए उदाहरण में, LoginComponentProvider
इंटरफ़ेस को तय किया जा सकता है
जो लॉगिन फ़्लो के लिए login
मॉड्यूल में LoginComponent
उपलब्ध कराता है:
Kotlin
interface LoginComponentProvider { fun provideLoginComponent(): LoginComponent }
Java
public interface LoginComponentProvider { public LoginComponent provideLoginComponent(); }
अब LoginActivity
, कोड के स्निपेट के बजाय उस इंटरफ़ेस का इस्तेमाल करेगा
ऊपर परिभाषित किया गया है:
Kotlin
class LoginActivity: Activity() { ... override fun onCreate(savedInstanceState: Bundle?) { loginComponent = (applicationContext as LoginComponentProvider) .provideLoginComponent() loginComponent.inject(this) ... } }
Java
public class LoginActivity extends Activity { ... @Override protected void onCreate(Bundle savedInstanceState) { loginComponent = ((LoginComponentProvider) getApplicationContext()) .provideLoginComponent(); loginComponent.inject(this); ... } }
अब MyApplication
को वह इंटरफ़ेस लागू करना होगा
ज़रूरी तरीके:
Kotlin
class MyApplication: Application(), LoginComponentProvider { // Reference to the application graph that is used across the whole app val appComponent = DaggerApplicationComponent.create() override fun provideLoginComponent(): LoginComponent { return appComponent.loginComponent().create() } }
Java
public class MyApplication extends Application implements LoginComponentProvider { // Reference to the application graph that is used across the whole app ApplicationComponent appComponent = DaggerApplicationComponent.create(); @Override public LoginComponent provideLoginComponent() { return appComponent.loginComponent.create(); } }
इस तरह, मल्टी-मॉड्यूल प्रोजेक्ट में डैगर सबकॉम्पोनेंट का इस्तेमाल इस तरह किया जा सकता है. सुविधा मॉड्यूल होने पर, सलूशन अलग-अलग होता है. इसकी वजह यह है कि मॉड्यूल एक-दूसरे पर निर्भर करते हैं.
फ़ीचर मॉड्यूल के साथ कॉम्पोनेंट डिपेंडेंसी
सुविधा वाले मॉड्यूल में, मॉड्यूल के काम करने का तरीका
एक-दूसरे को इन्वर्टेड करें. सुविधा वाले app
मॉड्यूल के बजाय
मॉड्यूल हैं, तो सुविधा वाले मॉड्यूल app
मॉड्यूल पर निर्भर करते हैं. दूसरी इमेज देखें
देखें कि मॉड्यूल कैसे स्ट्रक्चर किए जाते हैं.
डैगर में, कॉम्पोनेंट को अपने सबकॉम्पोनेंट के बारे में जानना ज़रूरी है. यह जानकारी
को पैरंट कॉम्पोनेंट में जोड़े गए डैगर मॉड्यूल में शामिल किया गया है (जैसे,
Android ऐप्लिकेशन में डैगर का इस्तेमाल करना में SubcomponentsModule
मॉड्यूल).
माफ़ करें, ऐप्लिकेशन और
फ़ीचर मॉड्यूल में, app
मॉड्यूल से सबकॉम्पोनेंट नहीं दिखता है, क्योंकि
यह बिल्ड पाथ में नहीं है. उदाहरण के लिए, a LoginComponent
को
login
फ़ीचर मॉड्यूल,
app
मॉड्यूल में ApplicationComponent
तय किया गया है.
डैगर में कॉम्पोनेंट डिपेंडेंसी नाम का एक तरीका है, जिसका इस्तेमाल करके इस समस्या को हल करें. चाइल्ड कॉम्पोनेंट, चाइल्ड कॉम्पोनेंट, पैरंट कॉम्पोनेंट पर निर्भर करता है. के साथ माता-पिता और बच्चे के बीच कोई संबंध न हो; अब कॉम्पोनेंट, दूसरों पर निर्भर करते हैं कुछ डिपेंडेंसी पाने के लिए. कॉम्पोनेंट को ग्राफ़ में दिए गए टाइप दिखाने चाहिए इनका इस्तेमाल किया जा सकता है.
उदाहरण के लिए: login
नाम का एक फ़ीचर मॉड्यूल बनाना चाहता है
LoginComponent
, जो इसमें उपलब्ध AppComponent
पर निर्भर करता है
app
Gradle मॉड्यूल.
यहां उन क्लास और AppComponent
की परिभाषाएं दी गई हैं जो इनमें शामिल हैं
app
Gradle मॉड्यूल:
Kotlin
// UserRepository's dependencies class UserLocalDataSource @Inject constructor() { ... } class UserRemoteDataSource @Inject constructor() { ... } // UserRepository is scoped to AppComponent @Singleton class UserRepository @Inject constructor( private val localDataSource: UserLocalDataSource, private val remoteDataSource: UserRemoteDataSource ) { ... } @Singleton @Component interface AppComponent { ... }
Java
// UserRepository's dependencies public class UserLocalDataSource { @Inject public UserLocalDataSource() {} } public class UserRemoteDataSource { @Inject public UserRemoteDataSource() { } } // UserRepository is scoped to AppComponent @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; } } @Singleton @Component public interface ApplicationComponent { ... }
आपके login
Gradle मॉड्यूल में, जिसमें app
Gradle मॉड्यूल शामिल है, आपके पास
LoginActivity
जिसे इंजेक्ट करने के लिए LoginViewModel
इंस्टेंस की ज़रूरत होती है:
Kotlin
// LoginViewModel depends on UserRepository that is scoped to AppComponent class LoginViewModel @Inject constructor( private val userRepository: UserRepository ) { ... }
Java
// LoginViewModel depends on UserRepository that is scoped to AppComponent public class LoginViewModel { private final UserRepository userRepository; @Inject public LoginViewModel(UserRepository userRepository) { this.userRepository = userRepository; } }
LoginViewModel
की, UserRepository
पर डिपेंडेंसी है जो उपलब्ध है और
दायरा AppComponent
है. चलिए, एक ऐसा LoginComponent
बनाते हैं जो इन चीज़ों पर निर्भर करता है
LoginActivity
इंजेक्ट करने के लिए AppComponent
:
Kotlin
// Use the dependencies attribute in the Component annotation to specify the // dependencies of this Component @Component(dependencies = [AppComponent::class]) interface LoginComponent { fun inject(activity: LoginActivity) }
Java
// Use the dependencies attribute in the Component annotation to specify the // dependencies of this Component @Component(dependencies = AppComponent.class) public interface LoginComponent { void inject(LoginActivity loginActivity); }
LoginComponent
, AppComponent
को डिपेंडेंसी के बारे में बताता है. इसके लिए, इसे
कॉम्पोनेंट के एनोटेशन का डिपेंडेंसी पैरामीटर. क्योंकि LoginActivity
यह कर पाएगा
डैगर से डाला जाएगा, तो इंटरफ़ेस में inject()
तरीका जोड़ें.
LoginComponent
बनाते समय, AppComponent
का एक इंस्टेंस ऐसा होना चाहिए
पास हुआ. इसके लिए, कॉम्पोनेंट फ़ैक्ट्री का इस्तेमाल करें:
Kotlin
@Component(dependencies = [AppComponent::class]) interface LoginComponent { @Component.Factory interface Factory { // Takes an instance of AppComponent when creating // an instance of LoginComponent fun create(appComponent: AppComponent): LoginComponent } fun inject(activity: LoginActivity) }
Java
@Component(dependencies = AppComponent.class) public interface LoginComponent { @Component.Factory interface Factory { // Takes an instance of AppComponent when creating // an instance of LoginComponent LoginComponent create(AppComponent appComponent); } void inject(LoginActivity loginActivity); }
अब LoginActivity
, LoginComponent
का एक इंस्टेंस बना सकता है और
inject()
तरीका.
Kotlin
class LoginActivity: Activity() { // You want Dagger to provide an instance of LoginViewModel from the Login graph @Inject lateinit var loginViewModel: LoginViewModel override fun onCreate(savedInstanceState: Bundle?) { // Gets appComponent from MyApplication available in the base Gradle module val appComponent = (applicationContext as MyApplication).appComponent // Creates a new instance of LoginComponent // Injects the component to populate the @Inject fields DaggerLoginComponent.factory().create(appComponent).inject(this) super.onCreate(savedInstanceState) // Now you can access loginViewModel } }
Java
public class LoginActivity extends Activity { // You want Dagger to provide an instance of LoginViewModel from the Login graph @Inject LoginViewModel loginViewModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Gets appComponent from MyApplication available in the base Gradle module AppComponent appComponent = ((MyApplication) getApplicationContext()).appComponent; // Creates a new instance of LoginComponent // Injects the component to populate the @Inject fields DaggerLoginComponent.factory().create(appComponent).inject(this); // Now you can access loginViewModel } }
LoginViewModel
, UserRepository
पर निर्भर है; और LoginComponent
होने के लिए
इसे AppComponent
से ऐक्सेस कर सकता है, AppComponent
को इसे बिना अनुमति के सार्वजनिक करना होगा
इसका इंटरफ़ेस:
Kotlin
@Singleton @Component interface AppComponent { fun userRepository(): UserRepository }
Java
@Singleton @Component public interface AppComponent { UserRepository userRepository(); }
डिपेंडेंट कॉम्पोनेंट वाले स्कोपिंग नियम, इनके साथ की तरह ही काम करते हैं
सबकॉम्पोनेंट. LoginComponent
, AppComponent
के इंस्टेंस का इस्तेमाल करता है, इसलिए
वे एक जैसे स्कोप वाली जानकारी का इस्तेमाल नहीं कर सकते.
अगर आपको LoginViewModel
को LoginComponent
में शामिल करना है, तो ऐसा करें
आपने पहले कस्टम @ActivityScope
एनोटेशन का इस्तेमाल किया था.
Kotlin
@ActivityScope @Component(dependencies = [AppComponent::class]) interface LoginComponent { ... } @ActivityScope class LoginViewModel @Inject constructor( private val userRepository: UserRepository ) { ... }
Java
@ActivityScope @Component(dependencies = AppComponent.class) public interface LoginComponent { ... } @ActivityScope public class LoginViewModel { private final UserRepository userRepository; @Inject public LoginViewModel(UserRepository userRepository) { this.userRepository = userRepository; } }
सबसे सही तरीके
ApplicationComponent
हमेशाapp
मॉड्यूल में होना चाहिए.अगर आपको फ़ील्ड इंजेक्शन डालना है, तो मॉड्यूल में डैगर कॉम्पोनेंट बनाएं नहीं डाला है या आपको एक खास फ़्लो के लिए ऑब्जेक्ट का स्कोप करने की ज़रूरत है आपका ऐप्लिकेशन.
Gradle मॉड्यूल, जो यूटिलिटी या हेल्पर के तौर पर होते हैं और जिनकी ज़रूरत नहीं होती का इस्तेमाल करके ग्राफ़ बनाना है (इसलिए आपको डैगर कॉम्पोनेंट की ज़रूरत होगी), उन क्लास के @provided और @Binds तरीकों वाले सार्वजनिक डैगर मॉड्यूल कंस्ट्रक्टर इंजेक्शन का समर्थन नहीं करते हैं.
सुविधा वाले मॉड्यूल के साथ Android ऐप्लिकेशन में डैगर का इस्तेमाल करने के लिए, कॉम्पोनेंट का इस्तेमाल करें आपके पास उपलब्ध डिपेंडेंसी को ऐक्सेस करने के लिए डिपेंडेंसी
ApplicationComponent
कोapp
मॉड्यूल में तय किया गया है.