একাধিক Gradle মডিউল সহ একটি প্রকল্প একটি মাল্টি-মডিউল প্রকল্প হিসাবে পরিচিত। একটি মাল্টি-মডিউল প্রজেক্টে যেটি কোনো বৈশিষ্ট্য মডিউল ছাড়াই একটি একক APK হিসেবে পাঠানো হয়, এটি একটি app
মডিউল থাকা সাধারণ বিষয় যেটি আপনার প্রকল্পের বেশিরভাগ মডিউলের উপর নির্ভর করতে পারে এবং একটি base
বা core
মডিউল যার উপর বাকি মডিউলগুলি সাধারণত নির্ভর করে। app
মডিউলে সাধারণত আপনার Application
ক্লাস থাকে, যেখানে base
মডিউলে আপনার প্রোজেক্টের সমস্ত মডিউল জুড়ে শেয়ার করা সমস্ত সাধারণ ক্লাস থাকে।
app
মডিউল আপনার অ্যাপ্লিকেশন উপাদান (উদাহরণস্বরূপ, নীচের ছবিতে ApplicationComponent
) ঘোষণা করার জন্য একটি ভাল জায়গা যা অন্যান্য উপাদানগুলির পাশাপাশি আপনার অ্যাপের একক টনগুলির প্রয়োজন হতে পারে এমন বস্তুগুলি সরবরাহ করতে পারে৷ উদাহরণ স্বরূপ, OkHttpClient
, JSON পার্সার, আপনার ডাটাবেসের অ্যাক্সেসর বা SharedPreferences
অবজেক্টের মতো ক্লাস যা core
মডিউলে সংজ্ঞায়িত করা যেতে পারে, app
মডিউলে সংজ্ঞায়িত ApplicationComponent
দ্বারা প্রদান করা হবে।
app
মডিউলে, আপনার আয়ু কম সহ অন্যান্য উপাদানও থাকতে পারে। একটি উদাহরণ হতে পারে একটি ব্যবহারকারী-নির্দিষ্ট কনফিগারেশন সহ একটি UserComponent
(যেমন একটি UserSession
) লগ ইন করার পরে৷
আপনার প্রজেক্টের বিভিন্ন মডিউলে, আপনি অন্তত একটি সাবকম্পোনেন্টকে সংজ্ঞায়িত করতে পারেন যেটি সেই মডিউলের জন্য নির্দিষ্ট যুক্তি আছে যেমন চিত্র 1 এ দেখা গেছে।
উদাহরণস্বরূপ, একটি login
মডিউলে, আপনার কাছে একটি কাস্টম @ModuleScope
টীকা সহ একটি LoginComponent
স্কোপ থাকতে পারে যা সেই বৈশিষ্ট্যের সাধারণ বস্তু যেমন একটি LoginRepository
প্রদান করতে পারে। সেই মডিউলের অভ্যন্তরে, আপনার কাছে অন্যান্য উপাদান থাকতে পারে যা একটি ভিন্ন কাস্টম সুযোগ সহ একটি LoginComponent
উপর নির্ভর করে, উদাহরণস্বরূপ @FeatureScope
একটি LoginActivityComponent
বা TermsAndConditionsComponent
যেখানে আপনি আরও বৈশিষ্ট্য-নির্দিষ্ট যুক্তি যেমন ViewModel
অবজেক্টের সুযোগ পেতে পারেন৷
Registration
মতো অন্যান্য মডিউলগুলির জন্য, আপনার একই রকম সেটআপ থাকবে।
একটি মাল্টি-মডিউল প্রকল্পের জন্য একটি সাধারণ নিয়ম হল যে একই স্তরের মডিউলগুলি একে অপরের উপর নির্ভর করবে না। যদি তারা তা করে তবে বিবেচনা করুন যে ভাগ করা যুক্তি (তাদের মধ্যে নির্ভরতা) প্যারেন্ট মডিউলের অংশ হওয়া উচিত কিনা। যদি তাই হয়, ক্লাসগুলিকে প্যারেন্ট মডিউলে সরানোর জন্য রিফ্যাক্টর; যদি না হয়, একটি নতুন মডিউল তৈরি করুন যা প্যারেন্ট মডিউলকে প্রসারিত করে এবং উভয় মূল মডিউল নতুন মডিউলকে প্রসারিত করে।
একটি সর্বোত্তম অনুশীলন হিসাবে, আপনি সাধারণত নিম্নলিখিত ক্ষেত্রে একটি মডিউলে একটি উপাদান তৈরি করবেন:
LoginActivityComponent
এর মতো আপনাকে ফিল্ড ইনজেকশন করতে হবে।LoginComponent
এর মতো আপনাকে অবজেক্ট স্কোপ করতে হবে।
যদি এই মামলাগুলির কোনটিই প্রযোজ্য না হয় এবং আপনাকে ড্যাগারকে বলতে হবে যে কীভাবে সেই মডিউল থেকে বস্তুগুলি সরবরাহ করতে হয়, সেই ক্লাসগুলির জন্য নির্মাণ ইনজেকশন সম্ভব না হলে @Provides
বা @Binds
পদ্ধতি সহ একটি ড্যাগার মডিউল তৈরি করুন এবং প্রকাশ করুন৷
ড্যাগার সাবকম্পোনেন্টের সাথে বাস্তবায়ন
অ্যান্ড্রয়েড অ্যাপের ডক পৃষ্ঠায় ড্যাগার ব্যবহার করে কীভাবে সাবকম্পোনেন্ট তৈরি এবং ব্যবহার করতে হয় তা কভার করে। যাইহোক, আপনি একই কোড ব্যবহার করতে পারবেন না কারণ বৈশিষ্ট্য মডিউলগুলি app
মডিউল সম্পর্কে জানে না। একটি উদাহরণ হিসাবে, আপনি যদি একটি সাধারণ লগইন প্রবাহ এবং আমাদের পূর্ববর্তী পৃষ্ঠায় থাকা কোড সম্পর্কে চিন্তা করেন তবে এটি আর কম্পাইল করে না:
কোটলিন
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) ... } }
জাভা
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
সম্পর্কে জানে না। এটি কাজ করার জন্য, আপনাকে বৈশিষ্ট্য মডিউলে একটি ইন্টারফেস সংজ্ঞায়িত করতে হবে যা একটি FeatureComponent
প্রদান করে যা MyApplication
প্রয়োগ করতে হবে।
নিম্নলিখিত উদাহরণে, আপনি একটি LoginComponentProvider
ইন্টারফেস সংজ্ঞায়িত করতে পারেন যা লগইন প্রবাহের জন্য login
মডিউলে একটি LoginComponent
প্রদান করে:
কোটলিন
interface LoginComponentProvider { fun provideLoginComponent(): LoginComponent }
জাভা
public interface LoginComponentProvider { public LoginComponent provideLoginComponent(); }
এখন, LoginActivity
উপরে সংজ্ঞায়িত কোডের স্নিপেটের পরিবর্তে সেই ইন্টারফেসটি ব্যবহার করবে:
কোটলিন
class LoginActivity: Activity() { ... override fun onCreate(savedInstanceState: Bundle?) { loginComponent = (applicationContext as LoginComponentProvider) .provideLoginComponent() loginComponent.inject(this) ... } }
জাভা
public class LoginActivity extends Activity { ... @Override protected void onCreate(Bundle savedInstanceState) { loginComponent = ((LoginComponentProvider) getApplicationContext()) .provideLoginComponent(); loginComponent.inject(this); ... } }
এখন, MyApplication
সেই ইন্টারফেসটি বাস্তবায়ন করতে হবে এবং প্রয়োজনীয় পদ্ধতিগুলি বাস্তবায়ন করতে হবে:
কোটলিন
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() } }
জাভা
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
মডিউলের উপর নির্ভর করে। মডিউলগুলি কীভাবে গঠন করা হয় তার উপস্থাপনার জন্য চিত্র 2 দেখুন।
ড্যাগারে, উপাদানগুলিকে তাদের সাবকম্পোনেন্টগুলি সম্পর্কে জানতে হবে। এই তথ্যটি প্যারেন্ট কম্পোনেন্টে যোগ করা একটি ড্যাগার মডিউলে অন্তর্ভুক্ত করা হয়েছে ( অ্যান্ড্রয়েড অ্যাপে ড্যাগার ব্যবহারে SubcomponentsModule
মডিউলের মতো)।
দুর্ভাগ্যবশত, অ্যাপ এবং বৈশিষ্ট্য মডিউলের মধ্যে বিপরীত নির্ভরতার সাথে, সাবকম্পোনেন্ট app
মডিউল থেকে দৃশ্যমান নয় কারণ এটি বিল্ড পাথে নেই। একটি উদাহরণ হিসাবে, একটি login
বৈশিষ্ট্য মডিউলে সংজ্ঞায়িত একটি LoginComponent
app
মডিউলে সংজ্ঞায়িত ApplicationComponent
এর একটি সাবকম্পোনেন্ট হতে পারে না।
ড্যাগারের উপাদান নির্ভরতা নামক একটি প্রক্রিয়া রয়েছে যা আপনি এই সমস্যাটি সমাধান করতে ব্যবহার করতে পারেন। শিশু উপাদানটি পিতামাতার উপাদানের একটি সাবকম্পোনেন্ট হওয়ার পরিবর্তে, শিশু উপাদানটি পিতামাতার উপাদানের উপর নির্ভরশীল। তার সাথে পিতা-মাতার সম্পর্ক নেই; এখন উপাদানগুলি নির্দিষ্ট নির্ভরতা পেতে অন্যের উপর নির্ভর করে। নির্ভরশীল উপাদানগুলি ব্যবহার করার জন্য উপাদানগুলিকে গ্রাফ থেকে প্রকারগুলি প্রকাশ করতে হবে।
উদাহরণস্বরূপ: login
নামক একটি বৈশিষ্ট্য মডিউল একটি LoginComponent
তৈরি করতে চায় যা app
গ্রেডল মডিউলে উপলব্ধ AppComponent
উপর নির্ভর করে।
নীচে ক্লাস এবং AppComponent
সংজ্ঞা রয়েছে যা app
গ্রেডল মডিউলের অংশ:
কোটলিন
// 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 { ... }
জাভা
// 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
গ্রেডল মডিউলে যেটিতে app
গ্রেডল মডিউল অন্তর্ভুক্ত রয়েছে, আপনার একটি LoginActivity
আছে যা ইনজেকশনের জন্য একটি LoginViewModel
দৃষ্টান্ত প্রয়োজন:
কোটলিন
// LoginViewModel depends on UserRepository that is scoped to AppComponent class LoginViewModel @Inject constructor( private val userRepository: UserRepository ) { ... }
জাভা
// 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
এর উপর নির্ভর করে:
কোটলিন
// 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) }
জাভা
// 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
Dagger দ্বারা ইনজেকশন করা হবে, ইন্টারফেসে inject()
মেথড যোগ করুন।
একটি LoginComponent
তৈরি করার সময়, AppComponent
এর একটি উদাহরণ পাস করতে হবে৷ এটি করতে উপাদান কারখানা ব্যবহার করুন:
কোটলিন
@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) }
জাভা
@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()
পদ্ধতিতে কল করতে পারে।
কোটলিন
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 } }
জাভা
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
এর ইন্টারফেসে এটি প্রকাশ করতে হবে:
কোটলিন
@Singleton @Component interface AppComponent { fun userRepository(): UserRepository }
জাভা
@Singleton @Component public interface AppComponent { UserRepository userRepository(); }
নির্ভরশীল উপাদানগুলির সাথে স্কোপিং নিয়মগুলি সাব-কম্পোনেন্টগুলির মতো একইভাবে কাজ করে। যেহেতু LoginComponent
AppComponent
এর একটি উদাহরণ ব্যবহার করে, তারা একই সুযোগের টীকা ব্যবহার করতে পারে না।
আপনি যদি LoginViewModel
LoginComponent
এ স্কোপ করতে চান, তাহলে আপনি কাস্টম @ActivityScope
টীকা ব্যবহার করে আগের মতই করবেন।
কোটলিন
@ActivityScope @Component(dependencies = [AppComponent::class]) interface LoginComponent { ... } @ActivityScope class LoginViewModel @Inject constructor( private val userRepository: UserRepository ) { ... }
জাভা
@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 মডিউলগুলির জন্য যেগুলিকে ইউটিলিটি বা সাহায্যকারী হিসাবে বোঝানো হয় এবং একটি গ্রাফ তৈরি করার প্রয়োজন নেই (এজন্য আপনার একটি ড্যাগার উপাদান প্রয়োজন), সেই ক্লাসগুলির @Provides এবং @Binds পদ্ধতিগুলির সাথে পাবলিক ড্যাগার মডিউলগুলি তৈরি করুন এবং প্রকাশ করুন কনস্ট্রাক্টর ইনজেকশন সমর্থন করে না।
ফিচার মডিউল সহ একটি অ্যান্ড্রয়েড অ্যাপে ড্যাগার ব্যবহার করতে,
app
মডিউলে সংজ্ঞায়িতApplicationComponent
দ্বারা প্রদত্ত নির্ভরতা অ্যাক্সেস করতে সক্ষম হতে উপাদান নির্ভরতা ব্যবহার করুন।