হিল্টের সাথে নির্ভরতা ইনজেকশন

হিল্ট হল অ্যান্ড্রয়েডের জন্য একটি ডিপেন্ডেন্সি ইনজেকশন লাইব্রেরি যা আপনার প্রকল্পে ম্যানুয়াল ডিপেন্ডেন্সি ইনজেকশন করার সময়কাল কমিয়ে দেয়। ম্যানুয়াল ডিপেন্ডেন্সি ইনজেকশন করার জন্য আপনাকে প্রতিটি ক্লাস এবং এর ডিপেন্ডেন্সি হাতে তৈরি করতে হবে এবং ডিপেন্ডেন্সি পুনঃব্যবহার এবং পরিচালনা করার জন্য কন্টেইনার ব্যবহার করতে হবে।

হিল্ট আপনার অ্যাপ্লিকেশনে DI ব্যবহারের একটি আদর্শ উপায় প্রদান করে, আপনার প্রকল্পের প্রতিটি অ্যান্ড্রয়েড ক্লাসের জন্য কন্টেইনার সরবরাহ করে এবং তাদের জীবনচক্র স্বয়ংক্রিয়ভাবে পরিচালনা করে। হিল্ট জনপ্রিয় DI লাইব্রেরি ড্যাগারের উপরে তৈরি করা হয়েছে যাতে ড্যাগার কম্পাইল-টাইম সঠিকতা, রানটাইম পারফরম্যান্স, স্কেলেবিলিটি এবং অ্যান্ড্রয়েড স্টুডিও সাপোর্ট থেকে উপকৃত হয়। আরও তথ্যের জন্য, হিল্ট এবং ড্যাগার দেখুন।

এই নির্দেশিকাটি হিল্ট এবং এর তৈরি কন্টেইনারগুলির মৌলিক ধারণাগুলি ব্যাখ্যা করে। এতে হিল্ট ব্যবহারের জন্য একটি বিদ্যমান অ্যাপকে কীভাবে বুটস্ট্র্যাপ করতে হয় তার একটি প্রদর্শনও অন্তর্ভুক্ত রয়েছে।

নির্ভরতা যোগ করা হচ্ছে

প্রথমে, আপনার প্রোজেক্টের রুট build.gradle ফাইলে hilt-android-gradle-plugin প্লাগইনটি যোগ করুন:

খাঁজকাটা

plugins {
  ...
  id 'com.google.dagger.hilt.android' version '2.57.1' apply false
}

কোটলিন

plugins {
  ...
  id("com.google.dagger.hilt.android") version "2.57.1" apply false
}

তারপর, Gradle প্লাগইনটি প্রয়োগ করুন এবং আপনার app/build.gradle ফাইলে এই নির্ভরতাগুলি যোগ করুন:

খাঁজকাটা

...
plugins {
  id 'com.google.devtools.ksp'
  id 'com.google.dagger.hilt.android'
}

android {
  ...
}

dependencies {
  implementation "com.google.dagger:hilt-android:2.57.1"
  ksp "com.google.dagger:hilt-compiler:2.57.1"
}

কোটলিন

plugins {
  id("com.google.devtools.ksp")
  id("com.google.dagger.hilt.android")
}

android {
  ...
}

dependencies {
  implementation("com.google.dagger:hilt-android:2.57.1")
  ksp("com.google.dagger:hilt-android-compiler:2.57.1")
}

হিল্ট জাভা ৮ বৈশিষ্ট্য ব্যবহার করে। আপনার প্রকল্পে জাভা ৮ সক্রিয় করতে, app/build.gradle ফাইলে নিম্নলিখিতগুলি যুক্ত করুন:

খাঁজকাটা

android {
  ...
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}

কোটলিন

android {
  ...
  compileOptions {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
  }
}

হিল্ট অ্যাপ্লিকেশন ক্লাস

Hilt ব্যবহার করে এমন সকল অ্যাপে অবশ্যই একটি Application ক্লাস থাকতে হবে যা @HiltAndroidApp দিয়ে টীকাযুক্ত।

@HiltAndroidApp হিল্টের কোড জেনারেশন ট্রিগার করে, যার মধ্যে আপনার অ্যাপ্লিকেশনের জন্য একটি বেস ক্লাস অন্তর্ভুক্ত থাকে যা অ্যাপ্লিকেশন-স্তরের নির্ভরতা ধারক হিসেবে কাজ করে।

কোটলিন

@HiltAndroidApp
class ExampleApplication : Application() { ... }

জাভা

@HiltAndroidApp
public class ExampleApplication extends Application { ... }

এই জেনারেটেড হিল্ট কম্পোনেন্টটি Application অবজেক্টের জীবনচক্রের সাথে সংযুক্ত থাকে এবং এটিতে নির্ভরতা প্রদান করে। অতিরিক্তভাবে, এটি অ্যাপের মূল কম্পোনেন্ট, যার অর্থ অন্যান্য কম্পোনেন্টগুলি এটি সরবরাহ করে এমন নির্ভরতা অ্যাক্সেস করতে পারে।

অ্যান্ড্রয়েড ক্লাসে নির্ভরতা ইনজেক্ট করুন

একবার আপনার Application ক্লাসে হিল্ট সেট আপ হয়ে গেলে এবং একটি অ্যাপ্লিকেশন-স্তরের উপাদান উপলব্ধ হয়ে গেলে, হিল্ট অন্যান্য অ্যান্ড্রয়েড ক্লাসগুলিতে নির্ভরতা প্রদান করতে পারে যাদের @AndroidEntryPoint অ্যানোটেশন রয়েছে:

কোটলিন

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() { ... }

জাভা

@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity { ... }

হিল্ট বর্তমানে নিম্নলিখিত অ্যান্ড্রয়েড ক্লাসগুলিকে সমর্থন করে:

  • Application ( @HiltAndroidApp ব্যবহার করে)
  • ViewModel ( @HiltViewModel ব্যবহার করে)
  • Activity
  • Fragment
  • View
  • Service
  • BroadcastReceiver

যদি আপনি @AndroidEntryPoint দিয়ে একটি Android ক্লাস অ্যানোটেট করেন, তাহলে আপনাকে অবশ্যই সেই Android ক্লাসগুলিও অ্যানোটেট করতে হবে যা এর উপর নির্ভর করে। উদাহরণস্বরূপ, যদি আপনি একটি ফ্র্যাগমেন্ট অ্যানোটেট করেন, তাহলে আপনাকে অবশ্যই সেই ফ্র্যাগমেন্টটি ব্যবহার করে এমন যেকোনো কার্যকলাপ অ্যানোটেট করতে হবে।

@AndroidEntryPoint আপনার প্রোজেক্টের প্রতিটি অ্যান্ড্রয়েড ক্লাসের জন্য একটি পৃথক Hilt কম্পোনেন্ট তৈরি করে। এই কম্পোনেন্টগুলি কম্পোনেন্ট হায়ারার্কিতে বর্ণিত তাদের নিজ নিজ প্যারেন্ট ক্লাস থেকে নির্ভরতা গ্রহণ করতে পারে।

একটি কম্পোনেন্ট থেকে নির্ভরতা পেতে, ফিল্ড ইনজেকশন সম্পাদনের জন্য @Inject অ্যানোটেশন ব্যবহার করুন:

কোটলিন

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {

  @Inject lateinit var analytics: AnalyticsAdapter
  ...
}

জাভা

@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity {

  @Inject
  AnalyticsAdapter analytics;
  ...
}

হিল্ট যেসব ক্লাস ইনজেক্ট করে, সেগুলোতে অন্যান্য বেস ক্লাসও থাকতে পারে যেগুলো ইনজেকশন ব্যবহার করে। যদি সেই ক্লাসগুলো অ্যাবস্ট্রাক্ট হয়, তাহলে @AndroidEntryPoint অ্যানোটেশনের প্রয়োজন হয় না।

কোন লাইফসাইকেল কলব্যাক একটি অ্যান্ড্রয়েড ক্লাসে ইনজেক্ট করা হয় সে সম্পর্কে আরও জানতে, কম্পোনেন্ট লাইফটাইম দেখুন।

হিল্ট বাইন্ডিং সংজ্ঞায়িত করুন

ফিল্ড ইনজেকশন সম্পাদনের জন্য, হিল্টকে জানতে হবে কিভাবে সংশ্লিষ্ট উপাদান থেকে প্রয়োজনীয় নির্ভরতার উদাহরণ প্রদান করতে হয়। একটি বাইন্ডিংয়ে নির্ভরতা হিসাবে একটি ধরণের উদাহরণ প্রদানের জন্য প্রয়োজনীয় তথ্য থাকে।

হিল্টকে বাইন্ডিং তথ্য প্রদানের একটি উপায় হল কনস্ট্রাক্টর ইনজেকশন । একটি ক্লাসের কনস্ট্রাক্টরে @Inject অ্যানোটেশন ব্যবহার করে হিল্টকে সেই ক্লাসের ইনস্ট্যান্স কীভাবে প্রদান করতে হয় তা বলুন:

কোটলিন

class AnalyticsAdapter @Inject constructor(
  private val service: AnalyticsService
) { ... }

জাভা

public class AnalyticsAdapter {

  private final AnalyticsService service;

  @Inject
  AnalyticsAdapter(AnalyticsService service) {
    this.service = service;
  }
  ...
}

একটি ক্লাসের অ্যানোটেটেড কনস্ট্রাক্টরের প্যারামিটার হল সেই ক্লাসের নির্ভরতা। উদাহরণে, AnalyticsAdapter AnalyticsService এর একটি নির্ভরতা রয়েছে। অতএব, Hilt-কে AnalyticsService এর উদাহরণ কীভাবে প্রদান করতে হয় তাও জানতে হবে।

হিল্ট মডিউল

কখনও কখনও একটি টাইপ কনস্ট্রাক্টর-ইনজেক্ট করা যায় না। এটি একাধিক কারণে ঘটতে পারে। উদাহরণস্বরূপ, আপনি একটি ইন্টারফেস কনস্ট্রাক্টর-ইনজেক্ট করতে পারবেন না। আপনি এমন একটি টাইপও কনস্ট্রাক্টর-ইনজেক্ট করতে পারবেন না যা আপনার মালিকানাধীন নয়, যেমন একটি বহিরাগত লাইব্রেরি থেকে একটি ক্লাস। এই ক্ষেত্রে, আপনি হিল্ট মডিউল ব্যবহার করে হিল্টকে বাইন্ডিং তথ্য সরবরাহ করতে পারেন।

হিল্ট মডিউল হলো এমন একটি ক্লাস যা @Module দিয়ে টীকা করা হয়। ড্যাগার মডিউলের মতো, এটি হিল্টকে নির্দিষ্ট ধরণের উদাহরণ কীভাবে প্রদান করতে হয় তা জানায়। ড্যাগার মডিউলের বিপরীতে, আপনাকে হিল্ট মডিউলগুলিকে @InstallIn দিয়ে টীকা করতে হবে যাতে হিল্টকে বলা যায় যে প্রতিটি মডিউল কোন অ্যান্ড্রয়েড ক্লাসে ব্যবহার বা ইনস্টল করা হবে।

হিল্ট মডিউলগুলিতে আপনার সরবরাহ করা নির্ভরতাগুলি সমস্ত জেনারেট করা উপাদানগুলিতে উপলব্ধ যা অ্যান্ড্রয়েড ক্লাসের সাথে সম্পর্কিত যেখানে আপনি হিল্ট মডিউল ইনস্টল করেন।

@Binds দিয়ে ইন্টারফেস ইনস্ট্যান্স ইনজেক্ট করুন

AnalyticsService উদাহরণটি বিবেচনা করুন। যদি AnalyticsService একটি ইন্টারফেস হয়, তাহলে আপনি এটি কনস্ট্রাক্টর-ইনজেক্ট করতে পারবেন না। পরিবর্তে, একটি Hilt মডিউলের ভিতরে @Binds দিয়ে টীকাযুক্ত একটি বিমূর্ত ফাংশন তৈরি করে Hilt কে বাইন্ডিং তথ্য প্রদান করুন।

@Binds অ্যানোটেশন হিল্টকে বলে যে যখন ইন্টারফেসের একটি উদাহরণ প্রদানের প্রয়োজন হয় তখন কোন বাস্তবায়ন ব্যবহার করতে হবে।

টীকাযুক্ত ফাংশনটি হিল্টকে নিম্নলিখিত তথ্য প্রদান করে:

  • ফাংশন রিটার্ন টাইপ হিল্টকে বলে যে ফাংশনটি কোন ইন্টারফেসের উদাহরণ প্রদান করে।
  • ফাংশন প্যারামিটার হিল্টকে বলে যে কোন বাস্তবায়ন প্রদান করতে হবে।

কোটলিন

interface AnalyticsService {
  fun analyticsMethods()
}

// Constructor-injected, because Hilt needs to know how to
// provide instances of AnalyticsServiceImpl, too.
class AnalyticsServiceImpl @Inject constructor(
  ...
) : AnalyticsService { ... }

@Module
@InstallIn(ActivityComponent::class)
abstract class AnalyticsModule {

  @Binds
  abstract fun bindAnalyticsService(
    analyticsServiceImpl: AnalyticsServiceImpl
  ): AnalyticsService
}

জাভা

public interface AnalyticsService {
  void analyticsMethods();
}

// Constructor-injected, because Hilt needs to know how to
// provide instances of AnalyticsServiceImpl, too.
public class AnalyticsServiceImpl implements AnalyticsService {
  ...
  @Inject
  AnalyticsServiceImpl(...) {
    ...
  }
}

@Module
@InstallIn(ActivityComponent.class)
public abstract class AnalyticsModule {

  @Binds
  public abstract AnalyticsService bindAnalyticsService(
    AnalyticsServiceImpl analyticsServiceImpl
  );
}

Hilt মডিউল AnalyticsModule @InstallIn(ActivityComponent.class) দিয়ে টীকাযুক্ত কারণ আপনি চান Hilt সেই নির্ভরতা ExampleActivity তে অন্তর্ভুক্ত করুক। এই টীকাটির অর্থ হল AnalyticsModule এর সমস্ত নির্ভরতা অ্যাপের সমস্ত কার্যকলাপে উপলব্ধ।

@Provides দিয়ে ইনস্ট্যান্স ইনজেক্ট করুন

ইন্টারফেসই একমাত্র ক্ষেত্রে নয় যেখানে আপনি কোনও টাইপ কনস্ট্রাক্টর-ইনজেক্ট করতে পারবেন না। কনস্ট্রাক্টর ইনজেকশনও সম্ভব নয় যদি আপনার ক্লাসটি না থাকে কারণ এটি একটি বহিরাগত লাইব্রেরি ( রেট্রোফিট , OkHttpClient , অথবা রুম ডাটাবেসের মতো ক্লাস) থেকে আসে, অথবা যদি বিল্ডার প্যাটার্ন দিয়ে ইনস্ট্যান্স তৈরি করতে হয়।

পূর্ববর্তী উদাহরণটি বিবেচনা করুন। যদি আপনি সরাসরি AnalyticsService ক্লাসের মালিক না হন, তাহলে আপনি Hilt মডিউলের ভিতরে একটি ফাংশন তৈরি করে এবং @Provides দিয়ে সেই ফাংশনটি টীকা করে Hilt কে এই ধরণের উদাহরণ কীভাবে প্রদান করতে হয় তা বলতে পারেন।

টীকাযুক্ত ফাংশনটি হিল্টকে নিম্নলিখিত তথ্য সরবরাহ করে:

  • ফাংশন রিটার্ন টাইপ হিল্টকে বলে যে ফাংশনটি কোন ধরণের ইনস্ট্যান্স প্রদান করে।
  • ফাংশন প্যারামিটারগুলি হিল্টকে সংশ্লিষ্ট ধরণের নির্ভরতা বলে।
  • ফাংশন বডি হিল্টকে নির্দেশ দেয় যে কীভাবে সংশ্লিষ্ট ধরণের একটি উদাহরণ প্রদান করতে হবে। হিল্ট যখনই সেই ধরণের একটি উদাহরণ প্রদানের প্রয়োজন হয় তখনই ফাংশন বডিটি কার্যকর করে।

কোটলিন

@Module
@InstallIn(ActivityComponent::class)
object AnalyticsModule {

  @Provides
  fun provideAnalyticsService(
    // Potential dependencies of this type
  ): AnalyticsService {
      return Retrofit.Builder()
               .baseUrl("https://example.com")
               .build()
               .create(AnalyticsService::class.java)
  }
}

জাভা

@Module
@InstallIn(ActivityComponent.class)
public class AnalyticsModule {

  @Provides
  public static AnalyticsService provideAnalyticsService(
    // Potential dependencies of this type
  ) {
      return new Retrofit.Builder()
               .baseUrl("https://example.com")
               .build()
               .create(AnalyticsService.class);
  }
}

একই ধরণের জন্য একাধিক বাইন্ডিং প্রদান করুন

যেসব ক্ষেত্রে আপনার Hilt-কে একই ধরণের নির্ভরতা এবং বিভিন্ন ধরণের বাস্তবায়ন প্রদানের প্রয়োজন হয়, সেক্ষেত্রে আপনাকে Hilt-কে একাধিক বাইন্ডিং প্রদান করতে হবে। আপনি কোয়ালিফায়ার ব্যবহার করে একই ধরণের জন্য একাধিক বাইন্ডিং সংজ্ঞায়িত করতে পারেন।

একটি কোয়ালিফায়ার হল একটি অ্যানোটেশন যা আপনি একটি নির্দিষ্ট বাইন্ডিং সনাক্ত করতে ব্যবহার করেন যখন সেই ধরণের একাধিক বাইন্ডিং সংজ্ঞায়িত থাকে।

উদাহরণটি বিবেচনা করুন। যদি আপনার AnalyticsService এ কল আটকানোর প্রয়োজন হয়, তাহলে আপনি একটি OkHttpClient অবজেক্ট ব্যবহার করতে পারেন যার মধ্যে একটি ইন্টারসেপ্টর রয়েছে। অন্যান্য পরিষেবার জন্য, আপনাকে অন্যভাবে কল আটকাতে হতে পারে। সেই ক্ষেত্রে, আপনাকে Hilt কে OkHttpClient এর দুটি ভিন্ন বাস্তবায়ন কীভাবে প্রদান করতে হয় তা বলতে হবে।

প্রথমে, @Binds বা @Provides পদ্ধতিগুলি টীকা করার জন্য আপনি যে কোয়ালিফায়ারগুলি ব্যবহার করবেন তা সংজ্ঞায়িত করুন:

কোটলিন

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class AuthInterceptorOkHttpClient

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class OtherInterceptorOkHttpClient

জাভা

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
private @interface AuthInterceptorOkHttpClient {}

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
private @interface OtherInterceptorOkHttpClient {}

তারপর, Hilt-কে জানতে হবে কিভাবে প্রতিটি কোয়ালিফায়ারের সাথে সঙ্গতিপূর্ণ ধরণের একটি উদাহরণ প্রদান করতে হয়। এই ক্ষেত্রে, আপনি @Provides সহ একটি Hilt মডিউল ব্যবহার করতে পারেন। উভয় পদ্ধতির রিটার্ন টাইপ একই, তবে কোয়ালিফায়ারগুলি তাদের দুটি ভিন্ন বাইন্ডিং হিসাবে লেবেল করে:

কোটলিন

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {

  @AuthInterceptorOkHttpClient
  @Provides
  fun provideAuthInterceptorOkHttpClient(
    authInterceptor: AuthInterceptor
  ): OkHttpClient {
      return OkHttpClient.Builder()
               .addInterceptor(authInterceptor)
               .build()
  }

  @OtherInterceptorOkHttpClient
  @Provides
  fun provideOtherInterceptorOkHttpClient(
    otherInterceptor: OtherInterceptor
  ): OkHttpClient {
      return OkHttpClient.Builder()
               .addInterceptor(otherInterceptor)
               .build()
  }
}

জাভা

@Module
@InstallIn(ActivityComponent.class)
public class NetworkModule {

  @AuthInterceptorOkHttpClient
  @Provides
  public static OkHttpClient provideAuthInterceptorOkHttpClient(
    AuthInterceptor authInterceptor
  ) {
      return new OkHttpClient.Builder()
                   .addInterceptor(authInterceptor)
                   .build();
  }

  @OtherInterceptorOkHttpClient
  @Provides
  public static OkHttpClient provideOtherInterceptorOkHttpClient(
    OtherInterceptor otherInterceptor
  ) {
      return new OkHttpClient.Builder()
                   .addInterceptor(otherInterceptor)
                   .build();
  }
}

আপনি সংশ্লিষ্ট কোয়ালিফায়ার দিয়ে ক্ষেত্র বা প্যারামিটারটি টীকা করে আপনার প্রয়োজনীয় নির্দিষ্ট প্রকারটি ইনজেক্ট করতে পারেন:

কোটলিন

// As a dependency of another class.
@Module
@InstallIn(ActivityComponent::class)
object AnalyticsModule {

  @Provides
  fun provideAnalyticsService(
    @AuthInterceptorOkHttpClient okHttpClient: OkHttpClient
  ): AnalyticsService {
      return Retrofit.Builder()
               .baseUrl("https://example.com")
               .client(okHttpClient)
               .build()
               .create(AnalyticsService::class.java)
  }
}

// As a dependency of a constructor-injected class.
class ExampleServiceImpl @Inject constructor(
  @AuthInterceptorOkHttpClient private val okHttpClient: OkHttpClient
) : ...

// At field injection.
@AndroidEntryPoint
class ExampleActivity: AppCompatActivity() {

  @AuthInterceptorOkHttpClient
  @Inject lateinit var okHttpClient: OkHttpClient
}

জাভা

// As a dependency of another class.
@Module
@InstallIn(ActivityComponent.class)
public class AnalyticsModule {

  @Provides
  public static AnalyticsService provideAnalyticsService(
    @AuthInterceptorOkHttpClient OkHttpClient okHttpClient
  ) {
      return new Retrofit.Builder()
                  .baseUrl("https://example.com")
                  .client(okHttpClient)
                  .build()
                  .create(AnalyticsService.class);
  }
}

// As a dependency of a constructor-injected class.
public class ExampleServiceImpl ... {

  private final OkHttpClient okHttpClient;

  @Inject
  ExampleServiceImpl(@AuthInterceptorOkHttpClient OkHttpClient okHttpClient) {
    this.okHttpClient = okHttpClient;
  }
}

// At field injection.
@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity {

  @AuthInterceptorOkHttpClient
  @Inject
  OkHttpClient okHttpClient;
  ...
}

সর্বোত্তম অনুশীলন হিসেবে, যদি আপনি একটি টাইপের সাথে একটি কোয়ালিফায়ার যোগ করেন, তাহলে সেই নির্ভরতা প্রদানের সম্ভাব্য সকল উপায়ে কোয়ালিফায়ার যোগ করুন। কোয়ালিফায়ার ছাড়া বেস বা সাধারণ বাস্তবায়ন ছেড়ে দিলে ত্রুটি-প্রবণতা দেখা দিতে পারে এবং এর ফলে হিল্ট ভুল নির্ভরতা ইনজেক্ট করতে পারে।

হিল্টে পূর্বনির্ধারিত যোগ্যতা অর্জনকারী দলসমূহ

হিল্ট কিছু পূর্বনির্ধারিত কোয়ালিফায়ার প্রদান করে। উদাহরণস্বরূপ, যেহেতু আপনার অ্যাপ্লিকেশন বা অ্যাক্টিভিটি থেকে Context ক্লাসের প্রয়োজন হতে পারে, হিল্ট @ApplicationContext এবং @ActivityContext কোয়ালিফায়ার প্রদান করে।

ধরুন, উদাহরণ থেকে AnalyticsAdapter ক্লাসের কার্যকলাপের প্রসঙ্গ প্রয়োজন। নিম্নলিখিত কোডটি দেখায় কিভাবে AnalyticsAdapter কে কার্যকলাপের প্রসঙ্গ প্রদান করতে হয়:

কোটলিন

class AnalyticsAdapter @Inject constructor(
    @ActivityContext private val context: Context,
    private val service: AnalyticsService
) { ... }

জাভা

public class AnalyticsAdapter {

  private final Context context;
  private final AnalyticsService service;

  @Inject
  AnalyticsAdapter(
    @ActivityContext Context context,
    AnalyticsService service
  ) {
    this.context = context;
    this.service = service;
  }
}

হিল্টে উপলব্ধ অন্যান্য পূর্বনির্ধারিত বাইন্ডিংয়ের জন্য, কম্পোনেন্ট ডিফল্ট বাইন্ডিং দেখুন।

অ্যান্ড্রয়েড ক্লাসের জন্য তৈরি উপাদান

প্রতিটি অ্যান্ড্রয়েড ক্লাসের জন্য যেখানে আপনি ফিল্ড ইনজেকশন করতে পারেন, সেখানে একটি সংশ্লিষ্ট হিল্ট কম্পোনেন্ট থাকে যা আপনি @InstallIn অ্যানোটেশনে উল্লেখ করতে পারেন। প্রতিটি হিল্ট কম্পোনেন্ট তার বাইন্ডিংগুলিকে সংশ্লিষ্ট অ্যান্ড্রয়েড ক্লাসে ইনজেক্ট করার জন্য দায়ী।

পূর্ববর্তী উদাহরণগুলি হিল্ট মডিউলগুলিতে ActivityComponent এর ব্যবহার প্রদর্শন করেছে।

হিল্ট নিম্নলিখিত উপাদানগুলি সরবরাহ করে:

হিল্ট উপাদান ইনজেক্টরের জন্য
SingletonComponent Application
ActivityRetainedComponent নিষিদ্ধ
ViewModelComponent ViewModel
ActivityComponent Activity
FragmentComponent Fragment
ViewComponent View
ViewWithFragmentComponent @WithFragmentBindings দিয়ে টীকাযুক্ত View
ServiceComponent Service

উপাদানের জীবনকাল

হিল্ট স্বয়ংক্রিয়ভাবে সংশ্লিষ্ট অ্যান্ড্রয়েড ক্লাসের জীবনচক্র অনুসরণ করে জেনারেট করা কম্পোনেন্ট ক্লাসের উদাহরণ তৈরি করে এবং ধ্বংস করে।

তৈরি করা উপাদান তৈরি করা হয়েছে ধ্বংস হয়েছে
SingletonComponent Application#onCreate() Application নষ্ট হয়ে গেছে
ActivityRetainedComponent Activity#onCreate() Activity#onDestroy()
ViewModelComponent ViewModel তৈরি করা হয়েছে ViewModel ধ্বংস হয়ে গেছে
ActivityComponent Activity#onCreate() Activity#onDestroy()
FragmentComponent Fragment#onAttach() Fragment#onDestroy()
ViewComponent View#super() View ধ্বংস হয়েছে
ViewWithFragmentComponent View#super() View ধ্বংস হয়েছে
ServiceComponent Service#onCreate() Service#onDestroy()

কম্পোনেন্ট স্কোপ

ডিফল্টরূপে, হিল্টের সমস্ত বাইন্ডিং আনস্কোপড থাকে। এর মানে হল যে আপনার অ্যাপ যখনই বাইন্ডিংয়ের অনুরোধ করবে, হিল্ট প্রয়োজনীয় ধরণের একটি নতুন ইনস্ট্যান্স তৈরি করবে।

উদাহরণে, যখনই Hilt অন্য ধরণের উপর নির্ভরতা হিসেবে অথবা ফিল্ড ইনজেকশনের মাধ্যমে AnalyticsAdapter প্রদান করে (যেমন ExampleActivity তে), Hilt AnalyticsAdapter এর একটি নতুন উদাহরণ প্রদান করে।

যাইহোক, হিল্ট একটি নির্দিষ্ট উপাদানের সাথে একটি বাইন্ডিংকে স্কোপ করার অনুমতি দেয়। হিল্ট যে উপাদানের সাথে বাইন্ডিংটি স্কোপ করা হয়েছে তার প্রতিটি উদাহরণের জন্য কেবল একবার স্কোপড বাইন্ডিং তৈরি করে এবং সেই বাইন্ডিংয়ের জন্য সমস্ত অনুরোধ একই উদাহরণ ভাগ করে।

নীচের টেবিলে প্রতিটি জেনারেট করা উপাদানের জন্য স্কোপ অ্যানোটেশন তালিকাভুক্ত করা হয়েছে:

অ্যান্ড্রয়েড ক্লাস তৈরি করা উপাদান ব্যাপ্তি
Application SingletonComponent @Singleton
Activity ActivityRetainedComponent @ActivityRetainedScoped
ViewModel ViewModelComponent @ViewModelScoped
Activity ActivityComponent @ActivityScoped
Fragment FragmentComponent @FragmentScoped
View ViewComponent @ViewScoped
@WithFragmentBindings দিয়ে টীকাযুক্ত View ViewWithFragmentComponent @ViewScoped
Service ServiceComponent @ServiceScoped

উদাহরণস্বরূপ, যদি আপনি @ActivityScoped ব্যবহার করে ActivityComponentAnalyticsAdapter ব্যবহার করেন, তাহলে Hilt সংশ্লিষ্ট কার্যকলাপের সময়কাল জুড়ে AnalyticsAdapter এর একই উদাহরণ প্রদান করবে:

কোটলিন

@ActivityScoped
class AnalyticsAdapter @Inject constructor(
  private val service: AnalyticsService
) { ... }

জাভা

@ActivityScoped
public class AnalyticsAdapter {

  private final AnalyticsService service;

  @Inject
  AnalyticsAdapter(AnalyticsService service) {
    this.service = service;
  }
  ...
}

ধরুন AnalyticsService একটি অভ্যন্তরীণ অবস্থা আছে যার জন্য প্রতিবার একই ইনস্ট্যান্স ব্যবহার করতে হবে—শুধুমাত্র ExampleActivity তে নয়, অ্যাপের যেকোনো জায়গায়। এই ক্ষেত্রে, AnalyticsService SingletonComponent তে অন্তর্ভুক্ত করা উপযুক্ত। এর ফলে যখনই কম্পোনেন্টটিকে AnalyticsService এর একটি ইনস্ট্যান্স প্রদান করতে হবে, তখন এটি প্রতিবার একই ইনস্ট্যান্স প্রদান করবে।

নিচের উদাহরণটি দেখায় কিভাবে Hilt মডিউলে একটি কম্পোনেন্টের সাথে বাইন্ডিং স্কোপ করা যায়। একটি বাইন্ডিং স্কোপ অবশ্যই সেই কম্পোনেন্টের স্কোপের সাথে মিলবে যেখানে এটি ইনস্টল করা আছে, তাই এই উদাহরণে আপনাকে ActivityComponent এর পরিবর্তে SingletonComponentAnalyticsService ইনস্টল করতে হবে:

কোটলিন

// If AnalyticsService is an interface.
@Module
@InstallIn(SingletonComponent::class)
abstract class AnalyticsModule {

  @Singleton
  @Binds
  abstract fun bindAnalyticsService(
    analyticsServiceImpl: AnalyticsServiceImpl
  ): AnalyticsService
}

// If you don't own AnalyticsService.
@Module
@InstallIn(SingletonComponent::class)
object AnalyticsModule {

  @Singleton
  @Provides
  fun provideAnalyticsService(): AnalyticsService {
      return Retrofit.Builder()
               .baseUrl("https://example.com")
               .build()
               .create(AnalyticsService::class.java)
  }
}

জাভা

// If AnalyticsService is an interface.
@Module
@InstallIn(SingletonComponent.class)
public abstract class AnalyticsModule {

  @Singleton
  @Binds
  public abstract AnalyticsService bindAnalyticsService(
    AnalyticsServiceImpl analyticsServiceImpl
  );
}

// If you don't own AnalyticsService.
@Module
@InstallIn(SingletonComponent.class)
public class AnalyticsModule {

  @Singleton
  @Provides
  public static AnalyticsService provideAnalyticsService() {
      return new Retrofit.Builder()
               .baseUrl("https://example.com")
               .build()
               .create(AnalyticsService.class);
  }
}

হিল্ট কম্পোনেন্ট স্কোপ সম্পর্কে আরও জানতে, অ্যান্ড্রয়েড এবং হিল্টে স্কোপিং দেখুন।

উপাদান শ্রেণিবিন্যাস

একটি কম্পোনেন্টে একটি মডিউল ইনস্টল করার ফলে এর বাইন্ডিংগুলিকে সেই কম্পোনেন্টের অন্যান্য বাইন্ডিং বা কম্পোনেন্ট হায়ারার্কিতে এর নীচের যেকোনো চাইল্ড কম্পোনেন্টের নির্ভরতা হিসাবে অ্যাক্সেস করা যায়:

ViewWithFragmentComponent হল FragmentComponent এর অধীনে। FragmentComponent এবং ViewComponent হল ActivityComponent এর অধীনে। ActivityComponent হল  ActivityRetainedComponent এর অধীনে। ViewModelComponent হল  ActivityRetainedComponent এর অধীনে। ActivityRetainedComponent এবং ServiceComponent  SingletonComponent এর অধীনে।
চিত্র ১. হিল্ট যে উপাদানগুলি তৈরি করে তার শ্রেণিবিন্যাস।

কম্পোনেন্ট ডিফল্ট বাইন্ডিং

প্রতিটি Hilt কম্পোনেন্টের সাথে ডিফল্ট বাইন্ডিং থাকে যা Hilt আপনার নিজস্ব কাস্টম বাইন্ডিংয়ে নির্ভরতা হিসেবে ইনজেক্ট করতে পারে। মনে রাখবেন যে এই বাইন্ডিংগুলি সাধারণ অ্যাক্টিভিটি এবং ফ্র্যাগমেন্ট ধরণের সাথে সামঞ্জস্যপূর্ণ, কোনও নির্দিষ্ট সাবক্লাসের সাথে নয়। এর কারণ হল Hilt সমস্ত অ্যাক্টিভিটি ইনজেক্ট করার জন্য একটি একক অ্যাক্টিভিটি কম্পোনেন্ট সংজ্ঞা ব্যবহার করে। প্রতিটি অ্যাক্টিভিটির এই কম্পোনেন্টের একটি আলাদা উদাহরণ রয়েছে।

অ্যান্ড্রয়েড কম্পোনেন্ট ডিফল্ট বাইন্ডিং
SingletonComponent Application
ActivityRetainedComponent Application
ViewModelComponent SavedStateHandle
ActivityComponent Application , Activity
FragmentComponent Application , Activity , Fragment
ViewComponent Application , Activity , View
ViewWithFragmentComponent Application , Activity , Fragment , View
ServiceComponent Application , Service

অ্যাপ্লিকেশন কনটেক্সট বাইন্ডিং @ApplicationContext ব্যবহার করেও উপলব্ধ। উদাহরণস্বরূপ:

কোটলিন

class AnalyticsServiceImpl @Inject constructor(
  @ApplicationContext context: Context
) : AnalyticsService { ... }

// The Application binding is available without qualifiers.
class AnalyticsServiceImpl @Inject constructor(
  application: Application
) : AnalyticsService { ... }

জাভা

public class AnalyticsServiceImpl implements AnalyticsService {

  private final Context context;

  @Inject
  AnalyticsAdapter(@ApplicationContext Context context) {
    this.context = context;
  }
}

// The Application binding is available without qualifiers.
public class AnalyticsServiceImpl implements AnalyticsService {

  private final Application application;

  @Inject
  AnalyticsAdapter(Application application) {
    this.application = application;
  }
}

@ActivityContext ব্যবহার করেও অ্যাক্টিভিটি কনটেক্সট বাইন্ডিং পাওয়া যায়। উদাহরণস্বরূপ:

কোটলিন

class AnalyticsAdapter @Inject constructor(
  @ActivityContext context: Context
) { ... }

// The Activity binding is available without qualifiers.
class AnalyticsAdapter @Inject constructor(
  activity: FragmentActivity
) { ... }

জাভা

public class AnalyticsAdapter {

  private final Context context;

  @Inject
  AnalyticsAdapter(@ActivityContext Context context) {
    this.context = context;
  }
}

// The Activity binding is available without qualifiers.
public class AnalyticsAdapter {

  private final FragmentActivity activity;

  @Inject
  AnalyticsAdapter(FragmentActivity activity) {
    this.activity = activity;
  }
}

হিল্ট দ্বারা সমর্থিত নয় এমন ক্লাসগুলিতে নির্ভরতা ইনজেক্ট করুন

হিল্টে সবচেয়ে সাধারণ অ্যান্ড্রয়েড ক্লাসের জন্য সাপোর্ট রয়েছে। তবে, আপনাকে এমন ক্লাসে ফিল্ড ইনজেকশন করতে হতে পারে যেগুলো হিল্ট সাপোর্ট করে না।

এই ক্ষেত্রে, আপনি @EntryPoint অ্যানোটেশন ব্যবহার করে একটি এন্ট্রি পয়েন্ট তৈরি করতে পারেন। একটি এন্ট্রি পয়েন্ট হল হিল্ট দ্বারা পরিচালিত কোড এবং নয় এমন কোডের মধ্যে সীমানা। এটি সেই বিন্দু যেখানে কোড প্রথমে হিল্ট দ্বারা পরিচালিত বস্তুর গ্রাফে প্রবেশ করে। এন্ট্রি পয়েন্টগুলি হিল্টকে এমন কোড ব্যবহার করার অনুমতি দেয় যা হিল্ট পরিচালনা করে না এবং নির্ভরতা গ্রাফের মধ্যে নির্ভরতা প্রদান করে।

উদাহরণস্বরূপ, Hilt সরাসরি কন্টেন্ট প্রোভাইডারদের সমর্থন করে না। যদি আপনি চান যে কোনও কন্টেন্ট প্রোভাইডার কিছু নির্ভরতা পেতে Hilt ব্যবহার করুক, তাহলে আপনাকে এমন একটি ইন্টারফেস সংজ্ঞায়িত করতে হবে যা আপনার পছন্দের প্রতিটি বাইন্ডিং টাইপের জন্য @EntryPoint দিয়ে টীকাযুক্ত এবং কোয়ালিফায়ার অন্তর্ভুক্ত করবে। তারপর @InstallIn যোগ করে কোন কম্পোনেন্টে এন্ট্রি পয়েন্ট ইনস্টল করতে হবে তা নিম্নরূপ উল্লেখ করুন:

কোটলিন

class ExampleContentProvider : ContentProvider() {

  @EntryPoint
  @InstallIn(SingletonComponent::class)
  interface ExampleContentProviderEntryPoint {
    fun analyticsService(): AnalyticsService
  }

  ...
}

জাভা

public class ExampleContentProvider extends ContentProvider {

  @EntryPoint
  @InstallIn(SingletonComponent.class)
  interface ExampleContentProviderEntryPoint {
    public AnalyticsService analyticsService();
  }
  ...
}

একটি এন্ট্রি পয়েন্ট অ্যাক্সেস করতে, EntryPointAccessors থেকে উপযুক্ত স্ট্যাটিক পদ্ধতি ব্যবহার করুন। প্যারামিটারটি হয় কম্পোনেন্ট ইনস্ট্যান্স অথবা @AndroidEntryPoint অবজেক্ট হওয়া উচিত যা কম্পোনেন্ট হোল্ডার হিসেবে কাজ করে। নিশ্চিত করুন যে আপনি যে কম্পোনেন্টটি প্যারামিটার হিসেবে পাস করছেন এবং EntryPointAccessors স্ট্যাটিক পদ্ধতি উভয়ই @EntryPoint ইন্টারফেসের @InstallIn অ্যানোটেশনে Android ক্লাসের সাথে মেলে:

কোটলিন

class ExampleContentProvider: ContentProvider() {
    ...

  override fun query(...): Cursor {
    val appContext = context?.applicationContext ?: throw IllegalStateException()
    val hiltEntryPoint =
      EntryPointAccessors.fromApplication(appContext, ExampleContentProviderEntryPoint::class.java)

    val analyticsService = hiltEntryPoint.analyticsService()
    ...
  }
}

জাভা

public class ExampleContentProvider extends ContentProvider {

  @Override
  public Cursor query(...) {
    Context appContext = getContext().getApplicationContext();
    ExampleContentProviderEntryPoint hiltEntryPoint =
      EntryPointAccessors.fromApplication(appContext, ExampleContentProviderEntryPoint.class);
    AnalyticsService analyticsService = hiltEntryPoint.analyticsService();
  }
}

এই উদাহরণে, আপনাকে এন্ট্রি পয়েন্টটি পুনরুদ্ধার করতে ApplicationContext ব্যবহার করতে হবে কারণ এন্ট্রি পয়েন্টটি SingletonComponent এ ইনস্টল করা আছে। আপনি যে বাইন্ডিংটি পুনরুদ্ধার করতে চেয়েছিলেন তা যদি ActivityComponent এ থাকে, তাহলে আপনি পরিবর্তে ActivityContext ব্যবহার করবেন।

হিল্ট এবং ড্যাগার

হিল্ট ড্যাগার ডিপেন্ডেন্সি ইনজেকশন লাইব্রেরির উপরে তৈরি, যা একটি অ্যান্ড্রয়েড অ্যাপ্লিকেশনে ড্যাগার অন্তর্ভুক্ত করার একটি আদর্শ উপায় প্রদান করে।

ড্যাগারের ক্ষেত্রে, হিল্টের লক্ষ্যগুলি নিম্নরূপ:

  • অ্যান্ড্রয়েড অ্যাপের জন্য ড্যাগার-সম্পর্কিত অবকাঠামো সহজ করার জন্য।
  • অ্যাপগুলির মধ্যে সেটআপ, পঠনযোগ্যতা এবং কোড ভাগাভাগি সহজ করার জন্য উপাদান এবং সুযোগের একটি স্ট্যান্ডার্ড সেট তৈরি করা।
  • বিভিন্ন বিল্ড প্রকারের জন্য বিভিন্ন বাইন্ডিং প্রদানের একটি সহজ উপায় প্রদান করা, যেমন টেস্টিং, ডিবাগ, অথবা রিলিজ।

যেহেতু অ্যান্ড্রয়েড অপারেটিং সিস্টেম তার নিজস্ব অনেক ফ্রেমওয়ার্ক ক্লাস ইন্সট্যান্টিয়েট করে, তাই অ্যান্ড্রয়েড অ্যাপে ড্যাগার ব্যবহার করার জন্য আপনাকে প্রচুর পরিমাণে বয়লারপ্লেট লিখতে হবে। হিল্ট অ্যান্ড্রয়েড অ্যাপ্লিকেশনে ড্যাগার ব্যবহারের সাথে জড়িত বয়লারপ্লেট কোড কমিয়ে দেয়। হিল্ট স্বয়ংক্রিয়ভাবে নিম্নলিখিতগুলি তৈরি করে এবং প্রদান করে:

  • ড্যাগারের সাথে অ্যান্ড্রয়েড ফ্রেমওয়ার্ক ক্লাসগুলিকে একীভূত করার জন্য উপাদানগুলি যা আপনাকে অন্যথায় হাতে তৈরি করতে হবে।
  • হিল্ট স্বয়ংক্রিয়ভাবে তৈরি করে এমন উপাদানগুলির সাথে ব্যবহারের জন্য স্কোপ অ্যানোটেশন
  • পূর্বনির্ধারিত বাইন্ডিং যা Android ক্লাস যেমন Application বা Activity প্রতিনিধিত্ব করে।
  • @ApplicationContext এবং @ActivityContext প্রতিনিধিত্ব করার জন্য পূর্বনির্ধারিত যোগ্যতা

ড্যাগার এবং হিল্ট কোড একই কোডবেসে সহাবস্থান করতে পারে। তবে, বেশিরভাগ ক্ষেত্রেই অ্যান্ড্রয়েডে ড্যাগারের সমস্ত ব্যবহার পরিচালনা করার জন্য হিল্ট ব্যবহার করা ভাল। ড্যাগার ব্যবহার করে এমন কোনও প্রকল্প হিল্টে স্থানান্তর করতে, মাইগ্রেশন গাইড এবং হিল্ট কোডল্যাবে আপনার ড্যাগার অ্যাপটি মাইগ্রেট করা দেখুন।

অতিরিক্ত সম্পদ

হিল্ট সম্পর্কে আরও জানতে, নিম্নলিখিত অতিরিক্ত সম্পদগুলি দেখুন।

নমুনা

কোডল্যাব

ব্লগ