निर्भरता इंजेक्शन का परिचय डिपेंडेंसी इंजेक्शन (DI) एक डिज़ाइन पैटर्न है जिसका उपयोग इनवर्जन ऑफ़ कंट्रोल (IoC) को लागू करने के लिए किया जाता है जहाँ निर्भरता बनाने और प्रबंधित करने का नियंत्रण एप्लिकेशन से बाहरी इकाई को स्थानांतरित किया जाता है। यह अधिक मॉड्यूलर, परीक्षण योग्य और रखरखाव योग्य कोड बनाने में मदद करता है। यह एक ऐसी तकनीक है जहाँ ऑब्जेक्ट बनाने की ज़िम्मेदारी कोड के अन्य भागों को हस्तांतरित की जाती है। यह ढीले युग्मन को बढ़ावा देता है, जिससे कोड अधिक मॉड्यूलर और प्रबंधित करने में आसान हो जाता है। कक्षाओं को ठीक से काम करने के लिए अक्सर अन्य कक्षाओं के संदर्भों की आवश्यकता होती है। उदाहरण के लिए, एक क्लास पर विचार करें जिसके लिए क्लास की आवश्यकता होती है। इन आवश्यक कक्षाओं को निर्भरता के रूप में जाना जाता है। क्लास को संचालित करने के लिए क्लास के इंस्टेंस पर निर्भर रहना पड़ता है। Library Book Library Book किसी क्लास के लिए आवश्यक ऑब्जेक्ट प्राप्त करने के तीन प्राथमिक तरीके हैं: : क्लास अपनी निर्भरताएँ स्वयं बनाता है और आरंभ करता है। उदाहरण के लिए, क्लास क्लास का अपना इंस्टेंस बनाएगा और आरंभ करेगा। स्व-निर्माण Library Book : क्लास बाहरी स्रोत से निर्भरताएँ पुनर्प्राप्त करता है। कुछ Android API, जैसे कि getters और , इस तरह से काम करते हैं। बाहरी पुनर्प्राप्ति Context getSystemService() : निर्भरताएँ क्लास को तब प्रदान की जाती हैं, जब इसे बनाया जाता है या उन विधियों के माध्यम से जिन्हें उनकी आवश्यकता होती है। उदाहरण के लिए, कंस्ट्रक्टर को पैरामीटर के रूप में इंस्टेंस प्राप्त होगा। निर्भरता इंजेक्शन Library Book तीसरा विकल्प निर्भरता इंजेक्शन है! DI के साथ, आप क्लास की निर्भरताएँ प्रदान करते हैं बजाय इसके कि क्लास इंस्टेंस उन्हें स्वयं प्राप्त करे। निर्भरता इंजेक्शन के बिना उदाहरण DI के बिना, एक जो अपनी स्वयं की निर्भरता बनाती है, वह इस तरह दिखाई दे सकती है: Library Book class Library { private Book book = new Book(); void open() { book.read(); } } public class Main { public static void main(String[] args) { Library library = new Library(); library.open(); } } यह DI का उदाहरण नहीं है क्योंकि क्लास अपनी खुद की बनाती है। यह समस्याग्रस्त हो सकता है क्योंकि: Library Book : और टाइट कपल्ड हैं। का एक उदाहरण एक प्रकार की का उपयोग करता है, जिससे उपवर्गों या वैकल्पिक कार्यान्वयन का उपयोग करना मुश्किल हो जाता है। टाइट कपलिंग Library Book Library Book : पर हार्ड निर्भरता परीक्षण को और अधिक चुनौतीपूर्ण बनाती है। के वास्तविक उदाहरण का उपयोग करती है, जिससे विभिन्न परीक्षण मामलों के लिए को संशोधित करने के लिए परीक्षण डबल्स के उपयोग को रोका जा सकता है। परीक्षण कठिनाइयाँ Book Library Book Book निर्भरता इंजेक्शन के साथ उदाहरण DI के साथ, के प्रत्येक इंस्टेंस द्वारा अपना स्वयं का ऑब्जेक्ट निर्मित करने के स्थान पर, उसे अपने कन्स्ट्रक्टर में पैरामीटर के रूप में ऑब्जेक्ट प्राप्त होता है: Library Book Book class Library { private Book book; Library(Book book) { this.book = book; } void open() { book.read(); } } public class Main { public static void main(String[] args) { Book book = new Book(); Library library = new Library(book); library.open(); } मुख्य फ़ंक्शन उपयोग करता है। चूँकि पर निर्भर करती है, इसलिए ऐप का एक इंस्टेंस बनाता है और फिर का इंस्टेंस बनाने के लिए इसका उपयोग करता है। इस DI-आधारित दृष्टिकोण के लाभ ये हैं: Library Library Book Book Library : आप के विभिन्न कार्यान्वयन को में पास कर सकते हैं। उदाहरण के लिए, आप का एक नया उपवर्ग परिभाषित कर सकते हैं जिसे कहा जाता है जिसे आप द्वारा उपयोग करना चाहते हैं। DI के साथ, आप बस का एक उदाहरण में पास करते हैं, और यह बिना किसी और बदलाव के काम करता है। Library की पुनः प्रयोज्यता Book Library Book EBook Library EBook Library : आप विभिन्न परिदृश्यों का परीक्षण करने के लिए टेस्ट डबल्स में पास हो सकते हैं। Library का आसान परीक्षण एक और DI उदाहरण एक परिदृश्य पर विचार करें जहां एक वर्ग एक वर्ग पर निर्भर करता है। DI के बिना, सीधे का एक उदाहरण बनाती है, जिससे विभिन्न प्रकार की सूचनाओं का उपयोग करना या विभिन्न अधिसूचना कार्यान्वयन के साथ सेवा का परीक्षण करना मुश्किल हो जाता है। NotificationService Notification NotificationService Notification DI को स्पष्ट करने के लिए, आइए इस उदाहरण को पुनः दोहराते हैं: interface Notification { void send(); } class EmailNotification implements Notification { @Override public void send() { // Send email notification } } class SMSNotification implements Notification { @Override public void send() { // Send SMS notification } } class NotificationService { void sendNotification(Notification notification) { notification.send(); } } अब, किसी विशिष्ट क्लास के बजाय इंटरफ़ेस पर निर्भर करती है। यह के विभिन्न कार्यान्वयनों को परस्पर उपयोग करने की अनुमति देता है। आप विधि के माध्यम से वह कार्यान्वयन सेट कर सकते हैं जिसका आप उपयोग करना चाहते हैं: NotificationService Notification Notification sendNotification NotificationService service = new NotificationService(); service.sendNotification(new EmailNotification()); service.sendNotification(new SMSNotification()); एंड्रॉयड में निर्भरता इंजेक्शन के तरीके डीआई के तीन मुख्य प्रकार हैं: : निर्भरताएँ विधियों के माध्यम से पारित की जाती हैं जिन्हें क्लास इंटरफ़ेस या किसी अन्य क्लास के माध्यम से एक्सेस कर सकता है। पिछला उदाहरण विधि इंजेक्शन को दर्शाता है। विधि (इंटरफ़ेस) इंजेक्शन : निर्भरताएं इसके कंस्ट्रक्टर के माध्यम से क्लास में पास की जाती हैं। कंस्ट्रक्टर इंजेक्शन class NotificationService { private final Notification notification; public NotificationService(Notification notification) { this.notification = notification; } public void sendNotification() { notification.send(); } } public class Main { public static void main(String[] args) { NotificationService service = new NotificationService(new EmailNotification()); service.sendNotification(); } } : कुछ Android फ़्रेमवर्क क्लास, जैसे कि एक्टिविटी और फ़्रैगमेंट, सिस्टम द्वारा इंस्टेंटिएट किए जाते हैं, इसलिए कंस्ट्रक्टर इंजेक्शन संभव नहीं है। फ़ील्ड इंजेक्शन के साथ, क्लास बनने के बाद निर्भरताएँ इंस्टेंटिएट की जाती हैं। 3. फ़ील्ड इंजेक्शन (या सेटर इंजेक्शन) class NotificationService { private Notification notification; public Notification getNotification() { return notification; } public void setNotification(Notification notification) { this.notification = notification; } public void sendNotification() { notification.send(); } } public class Main { public static void main(String[] args) { NotificationService service = new NotificationService(); service.setNotification(new EmailNotification()); service.sendNotification(); } } : निर्भरताएँ विधियों के माध्यम से प्रदान की जाती हैं, अक्सर एनोटेशन का उपयोग करके। 4. विधि इंजेक्शन @Inject निर्भरता इंजेक्शन के लाभ कक्षाएं अधिक पुन: प्रयोज्य हो जाती हैं और विशिष्ट कार्यान्वयन पर कम निर्भर होती हैं। यह नियंत्रण के व्युत्क्रम के कारण होता है, जहां कक्षाएं अब अपनी निर्भरताओं का प्रबंधन नहीं करती हैं, बल्कि किसी भी प्रदान की गई कॉन्फ़िगरेशन के साथ काम करती हैं। निर्भरताएं API सतह का हिस्सा हैं और इन्हें ऑब्जेक्ट निर्माण या संकलन समय पर सत्यापित किया जा सकता है, जिससे रिफैक्टरिंग आसान हो जाती है। चूंकि कोई वर्ग अपनी निर्भरताओं का प्रबंधन नहीं करता है, इसलिए विभिन्न परिदृश्यों को कवर करने के लिए परीक्षण के दौरान विभिन्न कार्यान्वयन पारित किए जा सकते हैं। स्वचालित निर्भरता इंजेक्शन पिछले उदाहरण में, आपने लाइब्रेरी का उपयोग किए बिना विभिन्न वर्गों की निर्भरताओं को मैन्युअल रूप से बनाया, प्रदान किया और प्रबंधित किया। इस दृष्टिकोण को मैन्युअल निर्भरता इंजेक्शन के रूप में जाना जाता है। जबकि यह सरल मामलों के लिए काम करता है, यह निर्भरता और वर्गों की संख्या बढ़ने पर बोझिल हो जाता है। मैन्युअल निर्भरता इंजेक्शन में कई कमियाँ हैं: : बड़े अनुप्रयोगों के लिए, सभी निर्भरताओं को प्रबंधित करना और उन्हें सही ढंग से जोड़ना बहुत सारे दोहराव वाले कोड का परिणाम हो सकता है। एक बहु-स्तरित वास्तुकला में, शीर्ष परत के लिए एक ऑब्जेक्ट बनाने के लिए इसके नीचे की परतों के लिए सभी निर्भरताएँ प्रदान करना आवश्यक है। उदाहरण के लिए, एक कंप्यूटर बनाने के लिए, आपको एक सीपीयू, एक मदरबोर्ड, रैम और अन्य घटकों की आवश्यकता होती है; और एक सीपीयू को ट्रांजिस्टर और कैपेसिटर की आवश्यकता हो सकती है। बॉयलरप्लेट कोड : जब आप पहले से निर्भरता का निर्माण नहीं कर सकते हैं - जैसे कि आलसी आरंभीकरण या आपके ऐप में विशिष्ट प्रवाह के लिए ऑब्जेक्ट्स को स्कोप करना - तो आपको मेमोरी में अपनी निर्भरता के जीवनकाल को प्रबंधित करने के लिए एक कस्टम कंटेनर (या निर्भरता ग्राफ) लिखने और बनाए रखने की आवश्यकता होती है। जटिल निर्भरता प्रबंधन लाइब्रेरी आपके लिए निर्भरताएँ बनाकर और प्रदान करके इस प्रक्रिया को स्वचालित कर सकती हैं। ये लाइब्रेरी दो श्रेणियों में आती हैं: : ये रनटाइम पर निर्भरताओं को जोड़ते हैं। प्रतिबिंब-आधारित समाधान : ये संकलन समय पर निर्भरताओं को जोड़ने के लिए कोड उत्पन्न करते हैं। स्थैतिक समाधान डैगर जावा, कोटलिन और एंड्रॉइड के लिए एक लोकप्रिय निर्भरता इंजेक्शन लाइब्रेरी है, जिसे Google द्वारा बनाए रखा जाता है। डैगर आपके लिए निर्भरता ग्राफ बनाकर और प्रबंधित करके आपके ऐप में DI को सरल बनाता है। यह पूरी तरह से स्थिर, संकलन-समय निर्भरता प्रदान करता है, जो Guice जैसे प्रतिबिंब-आधारित समाधानों से जुड़े कई विकास और प्रदर्शन मुद्दों को संबोधित करता है। प्रतिबिंब-आधारित समाधान ये फ्रेमवर्क रनटाइम पर निर्भरताओं को जोड़ते हैं: : एक रनटाइम DI फ्रेमवर्क जो निर्भरता को जोड़ने के लिए रिफ्लेक्शन का उपयोग करता है। इसे हल्का और तेज़ होने के लिए डिज़ाइन किया गया है, जो इसे Android एप्लिकेशन के लिए उपयुक्त बनाता है। टूथपिक स्थैतिक समाधान ये फ्रेमवर्क संकलन समय पर निर्भरताओं को जोड़ने के लिए कोड उत्पन्न करते हैं: : डैगर के शीर्ष पर निर्मित, हिल्ट एंड्रॉइड एप्लिकेशन में डैगर निर्भरता इंजेक्शन को शामिल करने का एक मानक तरीका प्रदान करता है हिल्ट । यह पूर्वनिर्धारित घटकों और स्कोप प्रदान करके डैगर के सेटअप और उपयोग को सरल बनाता है। : कोटलिन के लिए एक हल्का और सरल DI फ्रेमवर्क। कोइन निर्भरता को परिभाषित करने के लिए DSL का उपयोग करता है और इसे सेट अप करना और उपयोग करना आसान है। कोइन : कोटलिन-आधारित DI फ्रेमवर्क जो उपयोग करने और समझने में आसान है। यह निर्भरताओं के प्रबंधन के लिए एक सरल और लचीला API प्रदान करता है। कोडेन निर्भरता इंजेक्शन के विकल्प निर्भरता इंजेक्शन का एक विकल्प सर्विस लोकेटर पैटर्न है। यह डिज़ाइन पैटर्न कक्षाओं को उनकी ठोस निर्भरताओं से अलग करने में भी मदद करता है। आप सर्विस लोकेटर नामक एक क्लास बनाते हैं जो निर्भरताएँ बनाता और संग्रहीत करता है, उन्हें मांग पर प्रदान करता है। object ServiceLocator { fun getProcessor(): Processor = Processor() } class Computer { private val processor = ServiceLocator.getProcessor() fun start() { processor.run() } } fun main(args: Array<String>) { val computer = Computer() computer.start() } सर्विस लोकेटर पैटर्न निर्भरता इंजेक्शन से इस मामले में अलग है कि निर्भरता का उपभोग कैसे किया जाता है। सर्विस लोकेटर पैटर्न के साथ, क्लास अपनी ज़रूरत के अनुसार निर्भरता का अनुरोध करते हैं; निर्भरता इंजेक्शन के साथ, ऐप सक्रिय रूप से आवश्यक ऑब्जेक्ट प्रदान करता है। डैगर 2 क्या है? डैगर 2 एंड्रॉयड के लिए एक लोकप्रिय DI फ्रेमवर्क है। यह संकलन-समय कोड जनरेशन का उपयोग करता है और अपने उच्च प्रदर्शन के लिए जाना जाता है। डैगर 2 निर्भरता को संभालने के लिए आवश्यक कोड उत्पन्न करके निर्भरता इंजेक्शन की प्रक्रिया को सरल बनाता है, बॉयलरप्लेट को कम करता है और दक्षता में सुधार करता है। डैगर 2 एंड्रॉयड में निर्भरता इंजेक्शन के लिए एक एनोटेशन-आधारित लाइब्रेरी है। यहाँ मुख्य एनोटेशन और उनके उद्देश्य दिए गए हैं: : निर्भरता प्रदान करने वाली कक्षाओं को परिभाषित करने के लिए उपयोग किया जाता है। उदाहरण के लिए, एक मॉड्यूल रेट्रोफिट के लिए एक प्रदान कर सकता है। @मॉड्यूल ApiClient : निर्भरताएँ बनाने और वापस करने का तरीका निर्दिष्ट करने के लिए मॉड्यूल में विधियों को एनोटेट करता है। @Provides : निर्भरताओं का अनुरोध करने के लिए उपयोग किया जाता है। फ़ील्ड, कंस्ट्रक्टर और विधियों पर लागू किया जा सकता है। @Inject : एक इंटरफ़ेस जो और जोड़ता है। इसमें सभी मॉड्यूल शामिल हैं और यह एप्लिकेशन के लिए बिल्डर प्रदान करता है। @Component @Module @Inject : यह सुनिश्चित करता है कि निर्भरता का एक ही उदाहरण बनाया जाए। @सिंगलटन : निर्भरताएं प्रदान करने के लिए अमूर्त वर्गों में उपयोग किया जाता है, के समान लेकिन अधिक संक्षिप्त। @Binds @Provides डैगर अवयव डैगर आपके प्रोजेक्ट के लिए एक निर्भरता ग्राफ उत्पन्न कर सकता है, जिससे यह निर्धारित कर सकता है कि आवश्यकता पड़ने पर निर्भरता कहाँ से प्राप्त की जाए। इसे सक्षम करने के लिए, आपको एक इंटरफ़ेस बनाना होगा और इसे के साथ एनोटेट करना होगा। @Component इंटरफ़ेस के भीतर, आप उन विधियों को परिभाषित करते हैं जो आपके लिए आवश्यक कक्षाओं के उदाहरण लौटाते हैं (उदाहरण के लिए, )। एनोटेशन Dagger को एक कंटेनर बनाने का निर्देश देता है जिसमें वह सभी निर्भरताएँ हों जो उसके द्वारा प्रदर्शित प्रकारों को संतुष्ट करने के लिए आवश्यक हों। इस कंटेनर को Dagger घटक के रूप में जाना जाता है, और इसमें उन वस्तुओं का एक ग्राफ़ होता है जिन्हें Dagger उनकी निर्भरताओं के साथ प्रदान करना जानता है। @Component BookRepository @Component उदाहरण आइये से संबंधित एक उदाहरण पर विचार करें: LibraryRepository : कंस्ट्रक्टर में एनोटेशन जोड़ें ताकि Dagger को पता चले कि का इंस्टेंस कैसे बनाया जाए। कंस्ट्रक्टर को एनोटेट करें LibraryRepository @Inject LibraryRepository public class LibraryRepository { private final LocalLibraryDataSource localDataSource; private final RemoteLibraryDataSource remoteDataSource; @Inject public LibraryRepository(LocalLibraryDataSource localDataSource, RemoteLibraryDataSource remoteDataSource) { this.localDataSource = localDataSource; this.remoteDataSource = remoteDataSource; } } : इसी तरह, निर्भरताओं ( और ) के कंस्ट्रक्टर्स को एनोटेट करें ताकि डैगर को पता चले कि उन्हें कैसे बनाया जाए। 2. निर्भरताओं को एनोटेट करें LocalLibraryDataSource RemoteLibraryDataSource public class LocalLibraryDataSource { @Inject public LocalLibraryDataSource() { // Initialization code } } public class RemoteLibraryDataSource { private final LibraryService libraryService; @Inject public RemoteLibraryDataSource(LibraryService libraryService) { this.libraryService = libraryService; } } : निर्भरता ग्राफ को परिभाषित करने के लिए के साथ एनोटेट किया गया एक इंटरफ़ेस बनाएं। 3. घटक को परिभाषित करें @Component @Component public interface ApplicationComponent { LibraryRepository getLibraryRepository(); } जब आप प्रोजेक्ट बनाते हैं, तो Dagger आपके लिए इंटरफ़ेस का कार्यान्वयन उत्पन्न करता है, जिसे आमतौर पर नाम दिया जाता है। ApplicationComponent DaggerApplicationComponent प्रयोग अब आप उत्पन्न घटक का उपयोग अपने वर्गों के उदाहरण प्राप्त करने के लिए कर सकते हैं, जिनकी निर्भरताएं स्वचालित रूप से इंजेक्ट की जाती हैं: public class MainApplication extends Application { private ApplicationComponent applicationComponent; @Override public void onCreate() { super.onCreate(); applicationComponent = DaggerApplicationComponent.create(); } public ApplicationComponent getApplicationComponent() { return applicationComponent; } } अपनी गतिविधि या खंड में, आप इंस्टेंस को पुनः प्राप्त कर सकते हैं: LibraryRepository public class MainActivity extends AppCompatActivity { @Inject LibraryRepository libraryRepository; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ((MainApplication) getApplication()).getApplicationComponent().inject(this); // Use the injected libraryRepository } } डैगर 2 में प्रमुख अवधारणाएँ 1. मॉड्यूल ∘ मॉड्यूल की मुख्य अवधारणाएँ ∘ घटकों में मॉड्यूल शामिल करना 2. कार्यक्षेत्र 3. घटक 4. घटक निर्भरताएँ 5. रनटाइम बाइंडिंग 1. मॉड्यूल डैगर 2 में मॉड्यूल के साथ एनोटेट किए गए क्लास हैं जो घटकों को निर्भरता प्रदान करते हैं। उनमें या के साथ एनोटेट किए गए तरीके होते हैं जो यह निर्दिष्ट करते हैं कि निर्भरता कैसे बनाई और आपूर्ति की जाए। मॉड्यूल आपके एप्लिकेशन की ज़रूरत वाले ऑब्जेक्ट के निर्माण को व्यवस्थित और प्रबंधित करने के लिए आवश्यक हैं। @Module @Provides @Binds मॉड्यूल की मुख्य अवधारणाएँ @मॉड्यूल एनोटेशन: इस एनोटेशन का उपयोग किसी क्लास को डैगर मॉड्यूल के रूप में परिभाषित करने के लिए किया जाता है। मॉड्यूल क्लास में ऐसे तरीके होते हैं जो निर्भरता प्रदान करते हैं। @Provides एनोटेशन: इस एनोटेशन का उपयोग मॉड्यूल के भीतर विधियों पर यह इंगित करने के लिए किया जाता है कि विधि एक निश्चित निर्भरता प्रदान करती है। ये विधियाँ निर्भरता के उदाहरण बनाने और वापस करने के लिए जिम्मेदार हैं। @Binds एनोटेशन: इस एनोटेशन का उपयोग अमूर्त वर्गों में किसी कार्यान्वयन को इंटरफ़ेस से जोड़ने के लिए किया जाता है। यह से अधिक संक्षिप्त है और इसका उपयोग तब किया जाता है जब मॉड्यूल एक अमूर्त वर्ग होता है। @Provides मॉड्यूल का उदाहरण @Module public class NetworkModule { @Provides @Singleton Retrofit provideRetrofit() { return new Retrofit.Builder() .baseUrl("https://api.example.com") .addConverterFactory(GsonConverterFactory.create()) .build(); } @Provides @Singleton OkHttpClient provideOkHttpClient() { return new OkHttpClient.Builder() .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) .build(); } } इस उदाहरण में, के साथ एनोटेट किया गया एक क्लास है। इसमें के साथ एनोटेट किए गए दो तरीके हैं जो और के इंस्टेंस बनाते हैं और लौटाते हैं। NetworkModule @Module @Provides Retrofit OkHttpClient @Binds का उपयोग करना जब आपके पास एक इंटरफ़ेस और उसका कार्यान्वयन होता है, तो आप कार्यान्वयन को इंटरफ़ेस से जोड़ने के लिए उपयोग कर सकते हैं। यह उपयोग करने से ज़्यादा संक्षिप्त है। @Binds @Provides public interface ApiService { void fetchData(); } public class ApiServiceImpl implements ApiService { @Override public void fetchData() { // Implementation } } @Module public abstract class ApiModule { @Binds abstract ApiService bindApiService(ApiServiceImpl apiServiceImpl); } इस उदाहरण में, के साथ एनोटेट किया गया एक अमूर्त वर्ग है। से बाँधने के लिए विधि को के साथ एनोटेट किया गया है। ApiModule @Module ApiServiceImpl ApiService bindApiService @Binds मॉड्यूल को उनके द्वारा प्रदान की जाने वाली कार्यक्षमता के आधार पर व्यवस्थित किया जा सकता है। उदाहरण के लिए, आपके पास नेटवर्क संचालन, डेटाबेस संचालन और UI-संबंधित निर्भरताओं के लिए अलग-अलग मॉड्यूल हो सकते हैं। उदाहरण: : और जैसी नेटवर्क-संबंधित निर्भरताएं प्रदान करता है। NetworkModule Retrofit OkHttpClient : जैसी डेटाबेस-संबंधित निर्भरताएं प्रदान करता है. DatabaseModule RoomDatabase : और जैसी UI-संबंधित निर्भरताएं प्रदान करता है। UIModule ViewModel Presenter घटकों में मॉड्यूल शामिल करना मॉड्यूल को घटकों में शामिल किया जाता है ताकि उन वर्गों को निर्भरता प्रदान की जा सके जिन्हें उनकी आवश्यकता है। यहां बताया गया है कि आप इसे कैसे सेट कर सकते हैं: एप्लीकेशन घटक.जावा: @Singleton @Component(modules = {NetworkModule.class, DatabaseModule.class}) public interface ApplicationComponent { void inject(MyApplication application); } इस उदाहरण में, में अनुप्रयोग को निर्भरता प्रदान करने के लिए और शामिल हैं। ApplicationComponent NetworkModule DatabaseModule 2. कार्यक्षेत्र डैगर 2 में स्कोप एनोटेशन हैं जो निर्भरता के जीवनचक्र को परिभाषित करते हैं। वे सुनिश्चित करते हैं कि निर्भरता का एक ही उदाहरण बनाया गया है और निर्दिष्ट दायरे में साझा किया गया है। यह मेमोरी को कुशलतापूर्वक प्रबंधित करने और यह सुनिश्चित करने में मदद करता है कि निर्भरता का पुन: उपयोग उचित रूप से किया जाए। : अनुप्रयोग के संपूर्ण जीवनचक्र में निर्भरता का एकल उदाहरण सुनिश्चित करता है। सिंगलटन स्कोप : किसी गतिविधि के जीवनचक्र के भीतर निर्भरता का एक एकल उदाहरण सुनिश्चित करता है। गतिविधि क्षेत्र : फ़्रैगमेंट के जीवनचक्र के भीतर निर्भरता का एक एकल उदाहरण सुनिश्चित करता है। फ़्रैगमेंट स्कोप 1. सिंगलटन स्कोप : स्कोप यह सुनिश्चित करता है कि निर्भरता का एक एकल उदाहरण बनाया जाए और पूरे अनुप्रयोग के जीवनचक्र में साझा किया जाए। परिभाषा @Singleton इस क्षेत्र का उपयोग आम तौर पर उन निर्भरताओं के लिए किया जाता है जिन्हें पूरे अनुप्रयोग में साझा करने की आवश्यकता होती है, जैसे नेटवर्क क्लाइंट, डेटाबेस इंस्टेंस या साझा प्राथमिकताएं। उदाहरण: @Singleton @Component(modules = {NetworkModule.class, DatabaseModule.class}) public interface ApplicationComponent { void inject(MyApplication application); } इस उदाहरण में, एनोटेशन यह सुनिश्चित करता है कि और द्वारा प्रदान किए गए और इंस्टेंस सिंगलटन हैं और पूरे अनुप्रयोग में साझा किए गए हैं। @Singleton NetworkModule DatabaseModule Retrofit Database 2. गतिविधि का दायरा : (एक कस्टम स्कोप) यह सुनिश्चित करता है कि किसी गतिविधि के जीवनचक्र के भीतर निर्भरता का एक एकल उदाहरण बनाया और साझा किया जाए। परिभाषा @ActivityScope यह दायरा उन निर्भरताओं के लिए उपयोगी है जो किसी गतिविधि के लिए विशिष्ट हैं और जिन्हें प्रत्येक बार गतिविधि को पुनः बनाए जाने पर पुनः बनाया जाना चाहिए, जैसे प्रस्तुतकर्ता या दृश्य मॉडल। : उदाहरण @Scope @Retention(RetentionPolicy.RUNTIME) public @interface ActivityScope { } @ActivityScope @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); } इस उदाहरण में, एनोटेशन यह सुनिश्चित करता है कि द्वारा प्रदान की गई निर्भरताएं गतिविधि के जीवनचक्र तक सीमित हैं। @ActivityScope ActivityModule 3. खंड क्षेत्र : (एक अन्य कस्टम स्कोप) यह सुनिश्चित करता है कि निर्भरता का एक एकल उदाहरण फ्रेगमेंट के जीवनचक्र के भीतर बनाया और साझा किया जाए। परिभाषा @FragmentScope उपयोग मामला: यह दायरा उन निर्भरताओं के लिए उपयोगी है जो किसी फ्रेगमेंट के लिए विशिष्ट हैं और फ्रेगमेंट के पुनः निर्माण के समय हर बार उन्हें पुनः निर्मित किया जाना चाहिए, जैसे कि फ्रेगमेंट-विशिष्ट प्रस्तुतकर्ता या दृश्य मॉडल। : उदाहरण @Scope @Retention(RetentionPolicy.RUNTIME) public @interface FragmentScope { } @FragmentScope @Component(dependencies = ActivityComponent.class, modules = FragmentModule.class) public interface FragmentComponent { void inject(MyFragment myFragment); } इस उदाहरण में, एनोटेशन यह सुनिश्चित करता है कि द्वारा प्रदान की गई निर्भरताएं फ्रेगमेंट के जीवनचक्र तक सीमित हैं। @FragmentScope FragmentModule 3. घटक घटक निर्भरताएँ एक घटक को दूसरे पर निर्भर रहने देती हैं, जिससे निर्भरताओं का पुनः उपयोग संभव हो जाता है। घटक निर्भरता के दो मुख्य प्रकार हैं: : संपूर्ण अनुप्रयोग में आवश्यक निर्भरताएं प्रदान करता है। अनुप्रयोग घटक : किसी विशिष्ट गतिविधि के लिए आवश्यक निर्भरताएं प्रदान करता है। गतिविधि घटक 1. अनुप्रयोग घटक : एप्लिकेशन घटक निर्भरताएँ प्रदान करता है जो पूरे एप्लिकेशन में आवश्यक हैं। यह आमतौर पर के साथ स्कोप किया जाता है ताकि यह सुनिश्चित किया जा सके कि निर्भरताएँ पूरे एप्लिकेशन में साझा की जाती हैं। परिभाषा @Singleton इस घटक का उपयोग उन निर्भरताओं के लिए किया जाता है जिन्हें वैश्विक रूप से उपलब्ध होना आवश्यक है, जैसे नेटवर्क क्लाइंट, डेटाबेस इंस्टेंस या साझा प्राथमिकताएं। : उदाहरण @Singleton @Component(modules = {NetworkModule.class, DatabaseModule.class}) public interface ApplicationComponent { void inject(MyApplication application); } इस उदाहरण में, और इंस्टैंस प्रदान करने के लिए जिम्मेदार है, जिन्हें पूरे एप्लिकेशन में साझा किया जाता है। ApplicationComponent Retrofit Database 2. गतिविधि घटक : गतिविधि घटक ऐसी निर्भरताएँ प्रदान करता है जो किसी विशिष्ट गतिविधि के भीतर आवश्यक होती हैं। इसे आमतौर पर एक कस्टम स्कोप के साथ स्कोप किया जाता है, जैसे कि , यह सुनिश्चित करने के लिए कि हर बार गतिविधि को फिर से बनाए जाने पर निर्भरताएँ फिर से बनाई जाएँ। परिभाषा @ActivityScope इस घटक का उपयोग उन निर्भरताओं के लिए किया जाता है जो किसी गतिविधि के लिए विशिष्ट होती हैं, जैसे प्रस्तुतकर्ता या दृश्य मॉडल। : उदाहरण @ActivityScope @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); } इस उदाहरण में, , पर निर्भर करता है और के लिए विशिष्ट निर्भरताएँ प्रदान करता है। ActivityComponent ApplicationComponent MainActivity 4. घटक निर्भरताएँ घटक निर्भरताएँ एक घटक को दूसरे पर निर्भर रहने देती हैं, जिससे निर्भरताओं का पुनः उपयोग संभव हो जाता है। घटक निर्भरता के दो मुख्य प्रकार हैं: : एक उपघटक किसी अन्य घटक का संतान होता है और अपने मूल घटक की निर्भरताओं तक पहुंच सकता है। उपघटक : यह एक घटक को उपघटक बने बिना किसी अन्य घटक पर निर्भर रहने की अनुमति देता है। निर्भरता विशेषता 1. उपघटक: एक उपघटक दूसरे घटक का बच्चा होता है और अपने पैरेंट की निर्भरताओं तक पहुँच सकता है। उपघटक पैरेंट घटक के भीतर परिभाषित किए जाते हैं और इसके दायरे को विरासत में ले सकते हैं। : उदाहरण @ActivityScope @Subcomponent(modules = ActivityModule.class) public interface ActivitySubcomponent { void inject(MainActivity mainActivity); } इस उदाहरण में, मूल घटक का उपघटक है और इसकी निर्भरताओं तक पहुँच सकता है। ActivitySubcomponent 2. निर्भरता विशेषता यह किसी घटक को उपघटक बने बिना किसी अन्य घटक पर निर्भर रहने की अनुमति देता है। आश्रित घटक मूल घटक द्वारा प्रदान की गई निर्भरताओं तक पहुँच सकता है। : उदाहरण @ActivityScope @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); } इस उदाहरण में, , पर निर्भर करता है और इसकी निर्भरताओं तक पहुँच सकता है। ActivityComponent ApplicationComponent 5. रनटाइम बाइंडिंग डैगर 2 में रनटाइम बाइंडिंग निर्भरताओं के प्रावधान को संदर्भित करता है, जो उस संदर्भ के आधार पर रनटाइम पर बनाए और प्रबंधित किए जाते हैं जिसमें उनकी आवश्यकता होती है। : उन निर्भरताओं के लिए उपयोग किया जाता है जिन्हें अनुप्रयोग के रूप में लंबे समय तक बने रहने की आवश्यकता होती है। अनुप्रयोग संदर्भ : उन निर्भरताओं के लिए उपयोग किया जाता है जिन्हें गतिविधि के समान लंबे समय तक बने रहने की आवश्यकता होती है। गतिविधि संदर्भ 1. आवेदन संदर्भ : एप्लिकेशन संदर्भ एक ऐसा संदर्भ है जो पूरे एप्लिकेशन के जीवनचक्र से जुड़ा होता है। इसका उपयोग उन निर्भरताओं के लिए किया जाता है जिन्हें एप्लिकेशन के जितना ही समय तक जीवित रहना होता है। परिभाषा निर्भरताएँ जो पूरे एप्लिकेशन में साझा की जाती हैं और प्रत्येक गतिविधि या खंड के लिए उन्हें फिर से बनाने की आवश्यकता नहीं होती है। उदाहरणों में नेटवर्क क्लाइंट, डेटाबेस इंस्टेंस और साझा प्राथमिकताएँ शामिल हैं। : उदाहरण @Module public class AppModule { private final Application application; public AppModule(Application application) { this.application = application; } @Provides @Singleton Application provideApplication() { return application; } @Provides @Singleton Context provideApplicationContext() { return application.getApplicationContext(); } } इस उदाहरण में, एक सिंगलटन निर्भरता के रूप में एप्लिकेशन संदर्भ प्रदान करता है। विधि यह सुनिश्चित करती है कि प्रदान किया गया संदर्भ एप्लिकेशन के जीवनचक्र से जुड़ा हुआ है। AppModule provideApplicationContext 2. गतिविधि संदर्भ : गतिविधि संदर्भ एक संदर्भ है जो किसी विशिष्ट गतिविधि के जीवनचक्र से जुड़ा होता है। इसका उपयोग उन निर्भरताओं के लिए किया जाता है जिन्हें गतिविधि के समान ही लंबे समय तक जीवित रहने की आवश्यकता होती है। परिभाषा निर्भरताएँ जो किसी गतिविधि के लिए विशिष्ट होती हैं और हर बार गतिविधि को फिर से बनाए जाने पर उन्हें फिर से बनाया जाना चाहिए। उदाहरणों में व्यू मॉडल, प्रेजेंटर और UI-संबंधित निर्भरताएँ शामिल हैं। : उदाहरण @Module public class ActivityModule { private final Activity activity; public ActivityModule(Activity activity) { this.activity = activity; } @Provides @ActivityScope Activity provideActivity() { return activity; } @Provides @ActivityScope Context provideActivityContext() { return activity; } } इस उदाहरण में, गतिविधि संदर्भ को एक स्कोप्ड निर्भरता के रूप में प्रदान करता है। विधि यह सुनिश्चित करती है कि प्रदान किया गया संदर्भ गतिविधि के जीवनचक्र से जुड़ा हुआ है। ActivityModule provideActivityContext घटकों में रनटाइम बाइंडिंग का उपयोग करना इन रनटाइम बाइंडिंग का उपयोग करने के लिए, आपको अपने घटकों में संबंधित मॉड्यूल शामिल करने होंगे: : आवेदन घटक @Singleton @Component(modules = {AppModule.class, NetworkModule.class}) public interface ApplicationComponent { void inject(MyApplication application); Context getApplicationContext(); } : गतिविधि घटक @ActivityScope @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); Context getActivityContext(); } सन्दर्भों को शामिल करना एक बार जब आप अपने घटकों और मॉड्यूलों को सेट कर लेते हैं, तो आप आवश्यकतानुसार अपने वर्गों में संदर्भों को सम्मिलित कर सकते हैं। : एक गतिविधि में उदाहरण public class MainActivity extends AppCompatActivity { @Inject Context activityContext; @Inject Context applicationContext; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ApplicationComponent appComponent = ((MyApplication) getApplication()).getApplicationComponent(); ActivityComponent activityComponent = DaggerActivityComponent.builder() .applicationComponent(appComponent) .activityModule(new ActivityModule(this)) .build(); activityComponent.inject(this); // Use the injected contexts Log.d("MainActivity", "Activity Context: " + activityContext); Log.d("MainActivity", "Application Context: " + applicationContext); } } इस उदाहरण में, निर्भरता इंजेक्शन के माध्यम से गतिविधि संदर्भ और अनुप्रयोग संदर्भ दोनों प्राप्त करता है। यह गतिविधि को निर्भरताओं की विशिष्ट आवश्यकताओं के आधार पर उपयुक्त संदर्भ का उपयोग करने की अनुमति देता है। MainActivity उदाहरण: एंड्रॉयड एप्लीकेशन में डैगर 2 का उपयोग करना डैगर 2 की स्थापना अपने प्रोजेक्ट में Dagger 2 का उपयोग करने के लिए, आपको अपनी फ़ाइल में निम्नलिखित निर्भरताएँ जोड़नी होंगी: build.gradle dependencies { implementation 'com.google.dagger:dagger:2.x' annotationProcessor 'com.google.dagger:dagger-compiler:2.x' } Dagger 2 के नवीनतम संस्करण से प्रतिस्थापित करें। 2.x चरण 1: मॉड्यूल परिभाषित करें निर्भरता प्रदान करने के लिए एक मॉड्यूल बनाएँ। उदाहरण के लिए, एक इंस्टेंस प्रदान करने के लिए एक : Retrofit NetworkModule @Module public class NetworkModule { @Provides @Singleton Retrofit provideRetrofit() { return new Retrofit.Builder() .baseUrl("https://api.example.com") .addConverterFactory(GsonConverterFactory.create()) .build(); } } चरण 2: घटक परिभाषित करें मॉड्यूल और उन कक्षाओं को जोड़ने के लिए एक घटक बनाएं जिन्हें निर्भरता की आवश्यकता है: @Singleton @Component(modules = {NetworkModule.class}) public interface ApplicationComponent { void inject(MyApplication application); } चरण 3: निर्भरताएँ इंजेक्ट करें अपने क्लास में निर्भरता को इंजेक्ट करने के लिए घटक का उपयोग करें। उदाहरण के लिए, अपने क्लास में: Application public class MyApplication extends Application { private ApplicationComponent applicationComponent; @Override public void onCreate() { super.onCreate(); applicationComponent = DaggerApplicationComponent.builder() .networkModule(new NetworkModule()) .build(); applicationComponent.inject(this); } public ApplicationComponent getApplicationComponent() { return applicationComponent; } } चरण 4: इंजेक्टेड निर्भरता का उपयोग करें अब आप अपनी कक्षाओं में इंजेक्ट की गई निर्भरता का उपयोग कर सकते हैं। उदाहरण के लिए, किसी में: Activity public class MainActivity extends AppCompatActivity { @Inject Retrofit retrofit; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ((MyApplication) getApplication()).getApplicationComponent().inject(this); // Use the injected Retrofit instance // ... } } निष्कर्ष आइये इस विषय को संक्षेप में प्रस्तुत करें: DI का मुख्य उद्देश्य युग्मन को ढीला करना है, जिससे निर्भरताओं का प्रबंधन आसान हो जाता है। DI का उपयोग करके, आप कोड का लचीलापन बढ़ा सकते हैं और परीक्षण प्रक्रिया को सरल बना सकते हैं। DI एक जटिल विषय है जिसका परिदृश्य के आधार पर अलग-अलग कार्यान्वयन होता है। विभिन्न भाषाओं में DI की अपनी विशिष्टताएं होती हैं जो आपके कार्य करने के तरीके को प्रभावित कर सकती हैं। डैगर 2 निर्भरताओं को बनाने और प्रदान करने की प्रक्रिया को स्वचालित करता है, बॉयलरप्लेट कोड को कम करता है और रखरखाव में सुधार करता है। डैगर 2 संकलन-समय सुरक्षा प्रदान करता है, तथा यह सुनिश्चित करता है कि अनुप्रयोग चलाने से पहले सभी निर्भरताएं संतुष्ट हो जाएं। संकलन समय पर कोड उत्पन्न करके, डैगर 2 प्रतिबिंब-आधारित समाधानों से जुड़े प्रदर्शन ओवरहेड से बचता है।