Hilt ile bağımlılık yerleştirme (Görünümler)

Kavramlar ve Jetpack Compose uygulaması

Hilt, projenizde manuel bağımlılık ekleme işleminin standart kodunu azaltan, Android için bir bağımlılık ekleme kitaplığıdır. Manuel bağımlılık ekleme yapmak için her sınıfı ve bağımlılıklarını manuel olarak oluşturmanız ve bağımlılıkları yeniden kullanmak ve yönetmek için container'ları kullanmanız gerekir.

Hilt, projenizdeki her Android sınıfı için kapsayıcılar sağlayarak ve bunların yaşam döngülerini otomatik olarak yöneterek uygulamanızda DI kullanmanın standart bir yolunu sunar. Hilt, popüler DI kitaplığı Dagger'ın üzerine inşa edilmiştir. Bu sayede, Dagger'ın sunduğu derleme süresi doğruluğu, çalışma zamanı performansı, ölçeklenebilirlik ve Android Studio desteğinden yararlanır. Daha fazla bilgi için Hilt ve Dagger sayfasına bakın.

Bu kılavuzda, Hilt'in temel kavramları ve oluşturduğu kapsayıcılar açıklanmaktadır. Ayrıca, mevcut bir uygulamanın Hilt'i kullanmak için nasıl başlatılacağını gösteren bir demo da içerir.

Hilt uygulama sınıfı

Hilt kullanan tüm uygulamalar, @HiltAndroidApp ile ek açıklama eklenmiş bir Application sınıfı içermelidir.

@HiltAndroidApp, uygulamanız için uygulama düzeyinde bağımlılık kapsayıcısı olarak görev yapan bir temel sınıf da dahil olmak üzere Hilt'in kod oluşturma işlemini tetikler.

Kotlin

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

Java

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

Oluşturulan bu Hilt bileşeni, Application nesnesinin yaşam döngüsüne eklenir ve bu nesneye bağımlılıklar sağlar. Ayrıca uygulamanın üst bileşeni olduğu için diğer bileşenler, sağladığı bağımlılıklara erişebilir.

Android sınıflarına bağımlılık ekleme

Hilt, Application sınıfınızda ayarlandıktan ve uygulama düzeyinde bir bileşen kullanıma sunulduktan sonra @AndroidEntryPoint ek açıklamasına sahip diğer Android sınıflarına bağımlılıklar sağlayabilir:

Kotlin

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

Java

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

Hilt şu anda aşağıdaki Android sınıflarını desteklemektedir:

  • Application (@HiltAndroidApp kullanarak)
  • ViewModel (@HiltViewModel kullanarak)
  • Activity
  • Fragment
  • View
  • Service
  • BroadcastReceiver

Bir Android sınıfına @AndroidEntryPoint ile ek açıklama eklerseniz bu sınıfa bağlı Android sınıflarına da ek açıklama eklemeniz gerekir. Örneğin, bir parçaya ek açıklama eklerseniz bu parçayı kullandığınız tüm etkinliklere de ek açıklama eklemeniz gerekir.

@AndroidEntryPoint, projenizdeki her Android sınıfı için ayrı bir Hilt bileşeni oluşturur. Bu bileşenler, Bileşen hiyerarşisi bölümünde açıklandığı gibi ilgili üst sınıflarından bağımlılıklar alabilir.

Bir bileşenden bağımlılıkları almak için @Inject ek açıklamasını kullanarak alan yerleştirme işlemini gerçekleştirin:

Kotlin

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {

  @Inject lateinit var analytics: AnalyticsAdapter
  ...
}

Java

@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity {

  @Inject
  AnalyticsAdapter analytics;
  ...
}

Hilt'in eklediği sınıflar, ekleme kullanan başka temel sınıflara da sahip olabilir. Bu sınıflar soyutsa @AndroidEntryPoint ek açıklamasına gerek yoktur.

Bir Android sınıfının hangi yaşam döngüsü geri çağırma yöntemine eklendiği hakkında daha fazla bilgi edinmek için Bileşen yaşam süreleri başlıklı makaleyi inceleyin.

Hilt bağlamalarını tanımlama

Alan yerleştirme işlemini gerçekleştirmek için Hilt'in, ilgili bileşenden gerekli bağımlılıkların örneklerini nasıl sağlayacağını bilmesi gerekir. Bağlama, bir türün örneklerini bağımlılık olarak sağlamak için gereken bilgileri içerir.

Hilt'e bağlama bilgisi sağlamanın bir yolu oluşturucu yerleştirmedir. Hilt'e bir sınıfın örneklerini nasıl sağlayacağını bildirmek için sınıfın oluşturucusunda @Inject ek açıklamasını kullanın:

Kotlin

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

Java

public class AnalyticsAdapter {

  private final AnalyticsService service;

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

Bir sınıfın ek açıklamalı kurucusunun parametreleri, o sınıfın bağımlılıklarıdır. Örnekte, AnalyticsAdapter, AnalyticsService'e bağımlıdır. Bu nedenle Hilt, AnalyticsService örneklerinin nasıl sağlanacağını da bilmelidir.

Hilt modülleri

Bazen bir tür, oluşturucu yerleştirme yöntemiyle yerleştirilemez. Bunun birkaç nedeni olabilir. Örneğin, bir arayüze oluşturucu yerleştirme uygulayamazsınız. Ayrıca, harici bir kitaplıktaki sınıf gibi size ait olmayan bir türü oluşturucu yerleştirme yöntemiyle yerleştiremezsiniz. Bu gibi durumlarda, Hilt modüllerini kullanarak Hilt'e bağlama bilgileri sağlayabilirsiniz.

Hilt modülü, @Module ile ek açıklama eklenmiş bir sınıftır. Dagger modülü gibi, Hilt'e belirli türlerin örneklerini nasıl sağlayacağını bildirir. Dagger modüllerinden farklı olarak, Hilt modüllerine @InstallIn ek açıklamasını ekleyerek her modülün hangi Android sınıfında kullanılacağını veya yükleneceğini Hilt'e bildirmeniz gerekir.

Hilt modüllerinde sağladığınız bağımlılıklar, Hilt modülünü yüklediğiniz Android sınıfıyla ilişkili tüm oluşturulan bileşenlerde kullanılabilir.

@Binds ile arayüz örnekleri ekleme

AnalyticsService örneğini inceleyelim. AnalyticsService bir arayüzse oluşturucu yerleştirme yapamazsınız. Bunun yerine, bir Hilt modülünde @Binds ile ek açıklama eklenmiş soyut bir işlev oluşturarak Hilt'e bağlama bilgilerini sağlayın.

@Binds ek açıklaması, bir arayüzün örneğini sağlaması gerektiğinde hangi uygulamanın kullanılacağını Hilt'e bildirir.

Ek açıklamalı işlev, Hilt'e aşağıdaki bilgileri sağlar:

  • İşlev dönüş türü, Hilt'e işlevin hangi arayüzün örneklerini sağladığını bildirir.
  • İşlev parametresi, Hilt'e hangi uygulamanın sağlanacağını bildirir.

Kotlin

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
}

Java

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'in bu bağımlılığı ExampleActivity içine eklemesini istediğiniz için Hilt modülü AnalyticsModule, @InstallIn(ActivityComponent.class) ile ek açıklama eklenmiştir. Bu ek açıklama, AnalyticsModule içindeki tüm bağımlılıkların uygulamanın tüm etkinliklerinde kullanılabileceği anlamına gelir.

@Provides ile örnek ekleme

Oluşturucu yerleştirme yöntemini kullanamayacağınız tek durum arayüzler değildir. Sınıf harici bir kitaplıktan geldiği için (Retrofit, OkHttpClient veya Room veritabanları gibi sınıflar) sınıfa sahip değilseniz ya da örneklerin oluşturucu kalıbı ile oluşturulması gerekiyorsa oluşturucu yerleştirme de mümkün değildir.

Önceki örneği ele alalım. AnalyticsService sınıfının doğrudan sahibi değilseniz Hilt modülünde bir işlev oluşturup bu işleve @Provides ek açıklamasını ekleyerek Hilt'e bu türün örneklerini nasıl sağlayacağını söyleyebilirsiniz.

Ek açıklamalı işlev, Hilt kitaplığına aşağıdaki bilgileri sağlar:

  • İşlevin dönüş türü, Hilt'e işlevin hangi türün örneklerini sağladığını bildirir.
  • İşlev parametreleri, Hilt'e ilgili türün bağımlılıklarını bildirir.
  • İşlev gövdesi, Hilt'e ilgili türün bir örneğini nasıl sağlayacağını söyler. Hilt, bu türün bir örneğini sağlaması gerektiğinde işlev gövdesini yürütür.

Kotlin

@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)
  }
}

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);
  }
}

Aynı tür için birden fazla bağlama sağlama

Hilt'in aynı türün farklı uygulamalarını bağımlılık olarak sağlaması gereken durumlarda Hilt'e birden fazla bağlama sağlamanız gerekir. Niteleyiciler ile aynı tür için birden fazla bağlama tanımlayabilirsiniz.

Niteleyici, bir türün birden fazla bağlaması tanımlandığında o türün belirli bir bağlamasını tanımlamak için kullandığınız bir ek açıklamadır.

Örneği inceleyin. AnalyticsService çağrılarını kesmeniz gerekiyorsa kesici içeren bir OkHttpClient nesnesi kullanabilirsiniz. Diğer hizmetlerde aramaları farklı bir şekilde engellemeniz gerekebilir. Bu durumda, Hilt'e OkHttpClient için iki farklı uygulama sağlamayı bildirmeniz gerekir.

Öncelikle @Binds veya @Provides yöntemlerine ek açıklama eklemek için kullanacağınız niteleyicileri tanımlayın:

Kotlin

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

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

Java

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

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

Ardından Hilt'in, her niteleyiciye karşılık gelen türün bir örneğini nasıl sağlayacağını bilmesi gerekir. Bu durumda, @Provides ile bir Hilt modülü kullanabilirsiniz. Her iki yöntemin de dönüş türü aynıdır ancak niteleyiciler bunları iki farklı bağlama olarak etiketler:

Kotlin

@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()
  }
}

Java

@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();
  }
}

Alana veya parametreye karşılık gelen niteleyiciyle ek açıklama ekleyerek ihtiyacınız olan belirli türü ekleyebilirsiniz:

Kotlin

// 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
}

Java

// 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;
  ...
}

En iyi uygulama olarak, bir türe niteleyici eklerseniz bu bağımlılığı sağlamanın tüm olası yollarına niteleyici ekleyin. Temel veya ortak uygulamayı niteleyici olmadan bırakmak hataya açıktır ve Hilt kitaplığının yanlış bağımlıyı yerleştirmesine neden olabilir.

Hilt'te önceden tanımlanmış niteleyiciler

Hilt, önceden tanımlanmış bazı niteleyiciler sağlar. Örneğin, uygulamadan veya etkinlikten Context sınıfına ihtiyacınız olabileceği için Hilt, @ApplicationContext ve @ActivityContext niteleyicilerini sağlar.

Örnekteki AnalyticsAdapter sınıfının etkinliğin bağlamına ihtiyacı olduğunu varsayalım. Aşağıdaki kodda, etkinlik bağlamının AnalyticsAdapter öğesine nasıl sağlanacağı gösterilmektedir:

Kotlin

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

Java

public class AnalyticsAdapter {

  private final Context context;
  private final AnalyticsService service;

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

Hilt'te kullanılabilen diğer önceden tanımlanmış bağlamalar için Bileşen varsayılan bağlamaları bölümüne bakın.

Android sınıfları için oluşturulan bileşenler

Alan yerleştirme gerçekleştirebileceğiniz her Android sınıfı için @InstallIn ek açıklamasında başvurabileceğiniz ilişkili bir Hilt bileşeni vardır. Her Hilt bileşeni, bağlamalarını ilgili Android sınıfına eklemekten sorumludur.

Önceki örneklerde, Hilt modüllerinde ActivityComponent kullanımı gösterilmiştir.

Hilt aşağıdaki bileşenleri sağlar:

Hilt bileşeni Şu etkinliği başlatan:
SingletonComponent Application
ActivityRetainedComponent Yok
ViewModelComponent ViewModel
ActivityComponent Activity
FragmentComponent Fragment
ViewComponent View
ViewWithFragmentComponent View, @WithFragmentBindings ile ek açıklama ekledi
ServiceComponent Service

Bileşen kullanım ömürleri

Hilt, ilgili Android sınıflarının yaşam döngüsünü takip ederek oluşturulan bileşen sınıflarının örneklerini otomatik olarak oluşturur ve yok eder.

Oluşturulan bileşen Oluşturulma zamanı İmha edilme zamanı
SingletonComponent Application#onCreate() Application imha edildi
ActivityRetainedComponent Activity#onCreate() Activity#onDestroy()
ViewModelComponent ViewModel oluşturuldu ViewModel imha edildi
ActivityComponent Activity#onCreate() Activity#onDestroy()
FragmentComponent Fragment#onAttach() Fragment#onDestroy()
ViewComponent View#super() View imha edildi
ViewWithFragmentComponent View#super() View imha edildi
ServiceComponent Service#onCreate() Service#onDestroy()

Bileşen kapsamları

Varsayılan olarak, Hilt'teki tüm bağlamalar kapsamsızdır. Bu, uygulamanız bağlamayı her istediğinde Hilt'in gerekli türde yeni bir örnek oluşturduğu anlamına gelir.

Örnekte, Hilt başka bir türe bağımlılık olarak veya alan yerleştirme yoluyla (ExampleActivity örneğinde olduğu gibi) AnalyticsAdapter sağladığında her seferinde yeni bir AnalyticsAdapter örneği sağlar.

Ancak Hilt, bir bağlamanın belirli bir bileşene kapsamlandırılmasına da olanak tanır. Hilt, kapsamlı bağlamayı yalnızca bağlamanın kapsamına girdiği bileşenin örneği başına bir kez oluşturur ve bu bağlama için yapılan tüm istekler aynı örneği paylaşır.

Aşağıdaki tabloda, oluşturulan her bileşen için kapsam ek açıklamaları listelenmiştir:

Android sınıfı Oluşturulan bileşen Kapsam
Application SingletonComponent @Singleton
Activity ActivityRetainedComponent @ActivityRetainedScoped
ViewModel ViewModelComponent @ViewModelScoped
Activity ActivityComponent @ActivityScoped
Fragment FragmentComponent @FragmentScoped
View ViewComponent @ViewScoped
View, @WithFragmentBindings ile ek açıklama ekledi ViewWithFragmentComponent @ViewScoped
Service ServiceComponent @ServiceScoped

Örnekte, @ActivityScoped kullanarak AnalyticsAdapter öğesini ActivityComponent kapsamına alırsanız Hilt, ilgili etkinliğin ömrü boyunca AnalyticsAdapter öğesinin aynı örneğini sağlar:

Kotlin

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

Java

@ActivityScoped
public class AnalyticsAdapter {

  private final AnalyticsService service;

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

AnalyticsService sınıfının, yalnızca ExampleActivity içinde değil, uygulamanın her yerinde aynı örneğin kullanılmasını gerektiren bir dahili durumu olduğunu varsayalım. Bu durumda, AnalyticsService sınıfının kapsamını SingletonComponent olarak belirlemek uygun olur. Böylece bileşen, AnalyticsService örneği sağlaması gerektiğinde her seferinde aynı örneği sağlar.

Aşağıdaki örnekte, bir bağlamanın Hilt modülündeki bir bileşene nasıl kapsamlandırılacağı gösterilmektedir. Bağlamanın kapsamı, yüklendiği bileşenin kapsamıyla eşleşmelidir. Bu nedenle, bu örnekte AnalyticsService bileşenini ActivityComponent yerine SingletonComponent bileşenine yüklemeniz gerekir:

Kotlin

// 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)
  }
}

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);
  }
}

Hilt bileşen kapsamları hakkında daha fazla bilgi edinmek için Android ve Hilt'te kapsam belirleme başlıklı makaleyi inceleyin.

Bileşen hiyerarşisi

Bir bileşene modül yüklemek, bağlamalarına o bileşendeki veya bileşen hiyerarşisinde altındaki herhangi bir alt bileşendeki diğer bağlamaların bağımlılığı olarak erişilmesine olanak tanır:

ViewWithFragmentComponent, FragmentComponent'in altındadır. FragmentComponent
    ve ViewComponent, ActivityComponent'in altındadır. ActivityComponent, ActivityRetainedComponent'in altındadır. ViewModelComponent, ActivityRetainedComponent'in altındadır. ActivityRetainedComponent ve ServiceComponent, SingletonComponent'in altındadır.
Şekil 1. Hilt'in oluşturduğu bileşenlerin hiyerarşisi.

Bileşen varsayılan bağlamaları

Her Hilt bileşeni, Hilt'in kendi özel bağlamalarınıza bağımlılık olarak ekleyebileceği bir dizi varsayılan bağlama ile birlikte gelir. Bu bağlamaların belirli bir alt sınıfa değil, genel etkinlik ve parça türlerine karşılık geldiğini unutmayın. Bunun nedeni, Hilt'in tüm etkinlikleri eklemek için tek bir etkinlik bileşeni tanımı kullanmasıdır. Her etkinlikte bu bileşenin farklı bir örneği bulunur.

Android bileşeni Varsayılan bağlamalar
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

Uygulama bağlamı bağlama işlemi @ApplicationContext kullanılarak da yapılabilir. Örneğin:

Kotlin

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

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

Java

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;
  }
}

Etkinlik bağlamı bağlama işlemi @ActivityContext kullanılarak da yapılabilir. Örneğin:

Kotlin

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

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

Java

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;
  }
}

Hilt tarafından desteklenmeyen sınıflara bağımlılık ekleme

Hilt, en yaygın Android sınıflarını destekler. Ancak Hilt'in desteklemediği sınıflarda alan yerleştirme yapmanız gerekebilir.

Bu durumlarda, @EntryPoint ek açıklamasını kullanarak bir giriş noktası oluşturabilirsiniz. Giriş noktası, Hilt tarafından yönetilen kod ile yönetilmeyen kod arasındaki sınırdır. Kodun, Hilt'in yönettiği nesne grafiğine ilk girdiği noktadır. Giriş noktaları, Hilt'in bağımlılık grafiğinde bağımlılıkları sağlamak için yönetmediği kodu kullanmasına olanak tanır.

Örneğin, Hilt içerik sağlayıcıları doğrudan desteklemez. Bir içerik sağlayıcının bazı bağımlılıkları almak için Hilt kitaplığını kullanmasını istiyorsanız istediğiniz her bağlama türü için @EntryPoint ile ek açıklama eklenmiş bir arayüz tanımlamanız ve niteleyiciler eklemeniz gerekir. Ardından, giriş noktasının yükleneceği bileşeni belirtmek için @InstallIn öğesini aşağıdaki gibi ekleyin:

Kotlin

class ExampleContentProvider : ContentProvider() {

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

  ...
}

Java

public class ExampleContentProvider extends ContentProvider {

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

Bir giriş noktasına erişmek için EntryPointAccessors sınıfındaki uygun statik yöntemi kullanın. Parametre, bileşen örneği veya bileşen tutucu görevi gören @AndroidEntryPoint nesnesi olmalıdır. Parametre olarak ilettiğiniz bileşenin ve EntryPointAccessors statik yönteminin, @EntryPoint arayüzündeki @InstallIn ek açıklamasında bulunan Android sınıfıyla eşleştiğinden emin olun:

Kotlin

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()
    ...
  }
}

Java

public class ExampleContentProvider extends ContentProvider {

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

Bu örnekte, giriş noktası SingletonComponent içinde yüklü olduğundan giriş noktasını almak için ApplicationContext kullanmanız gerekir. Almak istediğiniz bağlama ActivityComponent içinde olsaydı ActivityContext kullanmanız gerekirdi.

Hilt ve Dagger

Hilt, Dagger bağımlılık ekleme kitaplığı üzerine kurulmuştur ve Dagger'ı bir Android uygulamasına dahil etmenin standart bir yolunu sunar.

Dagger ile ilgili olarak Hilt'in hedefleri şunlardır:

  • Android uygulamaları için Dagger ile ilgili altyapıyı basitleştirmek amacıyla
  • Uygulamalar arasında kurulumu, okunabilirliği ve kod paylaşımını kolaylaştırmak için standart bir bileşen ve kapsam grubu oluşturmak.
  • Test, hata ayıklama veya yayınlama gibi çeşitli derleme türlerine farklı bağlamalar sağlamanın kolay bir yolunu sunmak için.

Android işletim sistemi, kendi çerçeve sınıflarının çoğunu örneklendirdiği için Android uygulamasında Dagger kullanmak, önemli miktarda standart kod yazmanızı gerektirir. Hilt, Android uygulamalarında Dagger kullanırken gereken ortak metin kodunu azaltır. Hilt, aşağıdakileri otomatik olarak oluşturur ve sağlar:

  • Android çerçeve sınıflarını Dagger ile entegre etmek için kullanılan bileşenler. Bu bileşenler, aksi takdirde manuel olarak oluşturmanız gereken bileşenlerdir.
  • Hilt'in otomatik olarak oluşturduğu bileşenlerle kullanılacak kapsam ek açıklamaları
  • Application veya Activity gibi Android sınıflarını temsil eden önceden tanımlanmış bağlamalar.
  • @ApplicationContext ve @ActivityContext değerlerini temsil eden önceden tanımlanmış niteleyiciler.

Dagger ve Hilt kodu aynı kod tabanında bir arada bulunabilir. Ancak çoğu durumda, Android'de Dagger kullanımınızın tamamını yönetmek için Hilt'i kullanmak en iyisidir. Dagger kullanan bir projeyi Hilt'e taşımak için taşıma rehberini inceleyin.