paint-brush
Dagger 2 ile Bağımlılık Enjeksiyonu: Nedir, Temel Kavramlar ve Daha Fazlasıile@dilip2882
Yeni tarih

Dagger 2 ile Bağımlılık Enjeksiyonu: Nedir, Temel Kavramlar ve Daha Fazlası

ile Dilip Patel21m2024/08/28
Read on Terminal Reader

Çok uzun; Okumak

Bağımlılık Enjeksiyonu (DI), Kontrolün Tersine Çevrilmesini (IoC) uygulamak için kullanılan bir tasarım desenidir. Nesneleri oluşturma sorumluluğunun kodun diğer bölümlerine aktarıldığı bir tekniktir. Bu, gevşek bağlantıyı teşvik ederek kodu daha modüler ve yönetilmesi daha kolay hale getirir.
featured image - Dagger 2 ile Bağımlılık Enjeksiyonu: Nedir, Temel Kavramlar ve Daha Fazlası
Dilip Patel HackerNoon profile picture
0-item


Bağımlılık Enjeksiyonuna Giriş

Bağımlılık Enjeksiyonu (DI), bağımlılıkları oluşturma ve yönetme kontrolünün uygulamadan harici bir varlığa aktarıldığı Kontrolün Tersine Çevrilmesi'ni (IoC) uygulamak için kullanılan bir tasarım desenidir. Bu, daha modüler, test edilebilir ve sürdürülebilir kod oluşturmaya yardımcı olur. Nesneleri oluşturma sorumluluğunun kodun diğer bölümlerine aktarıldığı bir tekniktir. Bu, gevşek bağlantıyı teşvik ederek kodu daha modüler ve yönetilmesi daha kolay hale getirir.

Sınıfların düzgün çalışması için sıklıkla diğer sınıflara referanslara ihtiyacı vardır. Örneğin, Book sınıfı gerektiren bir Library sınıfını düşünün. Bu gerekli sınıflar bağımlılıklar olarak bilinir. Library sınıfının çalışması için Book sınıfının bir örneğine sahip olması gerekir.

hiperbeceri.org

Bir sınıfın ihtiyaç duyduğu nesneleri elde etmesinin üç temel yolu vardır:

  1. Kendi kendini yapılandırma : Sınıf kendi bağımlılıklarını oluşturur ve başlatır. Örneğin, Library sınıfı Book sınıfının kendi örneğini oluşturur ve başlatır.
  2. Harici alma : Sınıf, bağımlılıkları harici bir kaynaktan alır. Context getters ve getSystemService() gibi bazı Android API'leri bu şekilde çalışır.
  3. Bağımlılık Enjeksiyonu : Bağımlılıklar, sınıfa, ya inşa edildiğinde ya da bunları gerektiren yöntemler aracılığıyla sağlanır. Örneğin, Library kurucusu bir Book örneğini parametre olarak alır.

Üçüncü seçenek bağımlılık enjeksiyonudur! DI ile, sınıf örneğinin bunları kendisi edinmesi yerine, sınıfın bağımlılıklarını siz sağlarsınız.

Bağımlılık Enjeksiyonu Olmadan Örnek

DI olmadan, kendi Book bağımlılığını oluşturan bir Library şu şekilde görünebilir:

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

Bu bir DI örneği değildir çünkü Library sınıfı kendi Book oluşturur. Bu sorunlu olabilir çünkü:

  • Sıkı bağlantı : Library ve Book sıkı bir şekilde bağlıdır. Library örneği bir tür Book kullanır ve bu da alt sınıfların veya alternatif uygulamaların kullanılmasını zorlaştırır.
  • Test zorlukları : Book olan sert bağımlılık, testi daha zorlu hale getirir. Library Book gerçek bir örneğini kullanır ve farklı test durumları için Book değiştirmek için test kopyalarının kullanılmasını önler.

Bağımlılık Enjeksiyonu ile Örnek

DI ile, Library her örneği kendi Book nesnesini oluşturmak yerine, kurucusunda bir Book nesnesini parametre olarak alır:

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

Ana işlev Library kullanır. Library , Book bağlı olduğundan, uygulama Book bir örneğini oluşturur ve ardından bunu Library bir örneğini oluşturmak için kullanır. Bu DI tabanlı yaklaşımın faydaları şunlardır:

  • Library Yeniden Kullanılabilirliği : Book farklı uygulamalarını Library geçirebilirsiniz. Örneğin, Library kullanmasını istediğiniz Book EBook adında yeni bir alt sınıfını tanımlayabilirsiniz. DI ile, EBook bir örneğini Library geçirmeniz yeterlidir ve başka bir değişiklik yapmadan çalışır.
  • Library Kolay Test Edilmesi : Farklı senaryoları test etmek için test kopyalarını gönderebilirsiniz.

Başka bir DI Örneği

Bir NotificationService sınıfının bir Notification sınıfına dayandığı bir senaryoyu düşünün. DI olmadan, NotificationService doğrudan bir Notification örneği oluşturur ve bu da farklı bildirim türlerini kullanmayı veya hizmeti çeşitli bildirim uygulamalarıyla test etmeyi zorlaştırır.

DI'ı açıklamak için bu örneği yeniden düzenleyelim:

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

Artık NotificationService belirli bir sınıftan ziyade Notification arayüzüne bağlıdır. Bu, Notification farklı uygulamalarının birbirinin yerine kullanılabilmesine olanak tanır. Kullanmak istediğiniz uygulamayı sendNotification yöntemi aracılığıyla ayarlayabilirsiniz:

 NotificationService service = new NotificationService(); service.sendNotification(new EmailNotification()); service.sendNotification(new SMSNotification());

Android'de Bağımlılık Enjeksiyon Yöntemleri

DI’nin üç ana türü vardır:

  1. Yöntem (Arayüz) Enjeksiyonu : Bağımlılıklar, sınıfın bir arayüz veya başka bir sınıf aracılığıyla erişebileceği yöntemler aracılığıyla geçirilir. Önceki örnek yöntem enjeksiyonunu göstermektedir.
  2. Constructor Enjeksiyonu : Bağımlılıklar sınıfa, kendi constructor'ı aracılığıyla geçirilir.
 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(); } }

3. Alan Enjeksiyonu (veya Ayarlayıcı Enjeksiyonu) : Aktiviteler ve parçalar gibi belirli Android çerçeve sınıfları sistem tarafından örneklendirilir, bu nedenle oluşturucu enjeksiyonu mümkün değildir. Alan enjeksiyonuyla, bağımlılıklar sınıf oluşturulduktan sonra örneklendirilir.

 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. Metot Enjeksiyonu : Bağımlılıklar, çoğunlukla @Inject notasyonu kullanılarak metotlar aracılığıyla sağlanır.

Bağımlılık Enjeksiyonunun Avantajları

  • Sınıflar daha yeniden kullanılabilir hale gelir ve belirli uygulamalara daha az bağımlı hale gelir. Bu, sınıfların artık bağımlılıklarını yönetmediği ancak sağlanan herhangi bir yapılandırmayla çalıştığı kontrolün tersine çevrilmesinden kaynaklanır.
  • Bağımlılıklar API yüzeyinin bir parçasıdır ve nesne oluşturma veya derleme zamanında doğrulanabilir, bu da yeniden düzenlemeyi kolaylaştırır.
  • Bir sınıf bağımlılıklarını yönetmediğinden, çeşitli senaryoları kapsayacak şekilde test sırasında farklı uygulamalar geçirilebilir.

Otomatik Bağımlılık Enjeksiyonu

Önceki örnekte, bir kütüphane kullanmadan farklı sınıfların bağımlılıklarını manuel olarak oluşturdunuz, sağladınız ve yönettiniz. Bu yaklaşıma manuel bağımlılık enjeksiyonu denir. Basit durumlar için işe yarasa da, bağımlılık ve sınıf sayısı arttıkça zahmetli hale gelir. Manuel bağımlılık enjeksiyonunun birkaç dezavantajı vardır:

  • Kalıp Kod : Büyük uygulamalar için, tüm bağımlılıkları yönetmek ve bunları doğru şekilde bağlamak çok fazla tekrarlayan koda neden olabilir. Çok katmanlı bir mimaride, en üst katman için bir nesne oluşturmak, altındaki katmanlar için tüm bağımlılıkları sağlamayı gerektirir. Örneğin, bir bilgisayar oluşturmak için bir CPU, bir anakart, RAM ve diğer bileşenlere ihtiyacınız vardır; ve bir CPU'nun transistörlere ve kapasitörlere ihtiyacı olabilir.
  • Karmaşık Bağımlılık Yönetimi : Uygulamanızda tembel başlatmalar veya nesneleri belirli akışlara göre kapsamlandırma gibi önceden bağımlılıklar oluşturamadığınızda, bağımlılıklarınızın bellekteki yaşam sürelerini yönetmek için özel bir kapsayıcı (veya bağımlılık grafiği) yazmanız ve sürdürmeniz gerekir.

Kütüphaneler sizin için bağımlılıklar oluşturarak ve sağlayarak bu süreci otomatikleştirebilir. Bu kütüphaneler iki kategoriye ayrılır:

  1. Yansıma Tabanlı Çözümler : Bunlar bağımlılıkları çalışma zamanında birbirine bağlar.
  2. Statik Çözümler : Bunlar derleme zamanında bağımlılıkları bağlamak için kod üretir.

Dagger, Google tarafından yönetilen Java, Kotlin ve Android için popüler bir bağımlılık enjeksiyon kütüphanesidir. Dagger, sizin için bağımlılık grafiğini oluşturarak ve yöneterek uygulamanızdaki DI'ı basitleştirir. Guice gibi yansıma tabanlı çözümlerle ilişkili birçok geliştirme ve performans sorununu ele alan tamamen statik, derleme zamanı bağımlılıkları sağlar.

Yansımaya Dayalı Çözümler

Bu çerçeveler bağımlılıkları çalışma zamanında birbirine bağlar:

  1. Toothpick : Bağımlılıkları bağlamak için yansımayı kullanan bir çalışma zamanı DI çerçevesi. Hafif ve hızlı olacak şekilde tasarlanmıştır, bu da onu Android uygulamaları için uygun hale getirir.

Statik Çözümler

Bu çerçeveler, derleme zamanında bağımlılıkları bağlamak için kod üretir:

  1. Hilt : Dagger'ın üzerine inşa edilen Hilt, Dagger bağımlılık enjeksiyonunu bir Android uygulamasına dahil etmenin standart bir yolunu sağlar. Önceden tanımlanmış bileşenler ve kapsamlar sağlayarak Dagger'ın kurulumunu ve kullanımını basitleştirir .
  2. Koin : Kotlin için hafif ve basit bir DI framework'ü. Koin, bağımlılıkları tanımlamak için bir DSL kullanır ve kurulumu ve kullanımı kolaydır.
  3. Kodein : Kullanımı ve anlaşılması kolay Kotlin tabanlı bir DI framework'üdür. Bağımlılıkları yönetmek için basit ve esnek bir API sağlar.

Bağımlılık Enjeksiyonuna Alternatifler

Bağımlılık enjeksiyonuna bir alternatif, servis konum belirleyici örüntüsüdür. Bu tasarım örüntüsünün ayrıca sınıfları somut bağımlılıklarından ayırmaya yardımcı olur. Bağımlılıkları oluşturan ve depolayan, bunları talep üzerine sağlayan servis konum belirleyici olarak bilinen bir sınıf yaratırsınız.

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

Hizmet konum belirleme kalıbı, bağımlılıkların nasıl tüketildiği konusunda bağımlılık enjeksiyonundan farklıdır. Hizmet konum belirleme kalıbıyla, sınıflar ihtiyaç duydukları bağımlılıkları ister; bağımlılık enjeksiyonuyla, uygulama gerekli nesneleri proaktif olarak sağlar.

Dagger 2 Nedir?

Dagger 2, Android için popüler bir DI çerçevesidir. Derleme zamanı kod üretimi kullanır ve yüksek performansıyla bilinir. Dagger 2, bağımlılıkları işlemek için gerekli kodu üreterek bağımlılık enjeksiyonu sürecini basitleştirir, kalıpları azaltır ve verimliliği artırır.

Dagger 2, Android'de bağımlılık enjeksiyonu için açıklama tabanlı bir kütüphanedir. İşte temel açıklamalar ve amaçları:

  • @Module : Bağımlılıklar sağlayan sınıfları tanımlamak için kullanılır. Örneğin, bir modül Retrofit için bir ApiClient sağlayabilir.
  • @Provides : Bir modüldeki yöntemleri, bağımlılıkların nasıl oluşturulacağını ve döndürüleceğini belirtmek için açıklar.
  • @Inject : Bağımlılıkları istemek için kullanılır. Alanlara, oluşturuculara ve yöntemlere uygulanabilir.
  • @Component : @Module ve @Inject arasında köprü kuran bir arayüz. Tüm modülleri içerir ve uygulama için oluşturucu sağlar.
  • @Singleton : Bağımlılığın tek bir örneğinin oluşturulmasını sağlar.
  • @Binds : Soyut sınıflarda bağımlılıkları sağlamak için kullanılır, @Provides benzer ancak daha özdür.

Hançer Bileşenleri

Dagger, projeniz için bir bağımlılık grafiği üretebilir ve bu sayede ihtiyaç duyulduğunda bağımlılıkların nereden alınacağını belirleyebilir. Bunu etkinleştirmek için bir arayüz oluşturmanız ve onu @Component ile açıklamanız gerekir.

@Component arayüzünde, ihtiyaç duyduğunuz sınıfların örneklerini döndüren yöntemleri tanımlarsınız (örneğin, BookRepository ). @Component açıklaması, Dagger'a ifşa ettiği türleri karşılamak için gereken tüm bağımlılıkları içeren bir kapsayıcı oluşturmasını söyler. Bu kapsayıcı bir Dagger bileşeni olarak bilinir ve Dagger'ın bağımlılıklarıyla birlikte nasıl sağlayacağını bildiği nesnelerin bir grafiğini içerir.


Örnek

LibraryRepository içeren bir örneği ele alalım:

  1. Oluşturucuyu Açıklama : Dagger'ın LibraryRepository örneğini nasıl oluşturacağını bilmesi için LibraryRepository oluşturucusuna bir @Inject açıklaması ekleyin.
 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. Bağımlılıkları Açıklama : Benzer şekilde, bağımlılıkların ( LocalLibraryDataSource ve RemoteLibraryDataSource ) oluşturucularını da açıklama ekleyerek Dagger'ın bunları nasıl oluşturacağını bilmesini sağlayın.

 public class LocalLibraryDataSource { @Inject public LocalLibraryDataSource() { // Initialization code } } public class RemoteLibraryDataSource { private final LibraryService libraryService; @Inject public RemoteLibraryDataSource(LibraryService libraryService) { this.libraryService = libraryService; } }

3. Bileşeni Tanımlayın : Bağımlılık grafiğini tanımlamak için @Component ile açıklamalı bir arayüz oluşturun.

 @Component public interface ApplicationComponent { LibraryRepository getLibraryRepository(); }

Projeyi derlediğinizde Dagger sizin için ApplicationComponent arayüzünün bir uygulamasını üretir, genellikle DaggerApplicationComponent olarak adlandırılır.

Kullanım

Artık oluşturulan bileşeni, bağımlılıkları otomatik olarak eklenen sınıflarınızın örneklerini elde etmek için kullanabilirsiniz:

 public class MainApplication extends Application { private ApplicationComponent applicationComponent; @Override public void onCreate() { super.onCreate(); applicationComponent = DaggerApplicationComponent.create(); } public ApplicationComponent getApplicationComponent() { return applicationComponent; } }

Etkinliğinizde veya parçanızda LibraryRepository örneğini alabilirsiniz:

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

Dagger 2'deki Temel Kavramlar

1. Modüller
∘ Modüllerin Temel Kavramları
∘ Bileşenlere Modüller Dahil Etme
2. Kapsamlar
3. Bileşenler
4. Bileşen Bağımlılıkları
5. Çalışma Zamanı Bağlamaları

1. Modüller

Dagger 2'deki modüller, bileşenlere bağımlılıklar sağlayan @Module ile açıklanan sınıflardır. Bağımlılıkların nasıl oluşturulacağını ve sağlanacağını belirtmek için @Provides veya @Binds ile açıklanan yöntemler içerirler. Modüller, uygulamanızın ihtiyaç duyduğu nesnelerin oluşturulmasını organize etmek ve yönetmek için önemlidir.

Modüllerin Temel Kavramları

  1. @Module Açıklaması: Bu açıklama, bir sınıfı Dagger modülü olarak tanımlamak için kullanılır. Bir modül sınıfı, bağımlılıklar sağlayan yöntemler içerir.
  2. @Provides Annotation: Bu açıklama, bir modül içindeki yöntemlerde, yöntemin belirli bir bağımlılığı sağladığını belirtmek için kullanılır. Bu yöntemler, bağımlılıkların örneklerini oluşturmaktan ve döndürmekten sorumludur.
  3. @Binds Açıklaması: Bu açıklama, soyut sınıflarda bir uygulamayı bir arayüze bağlamak için kullanılır. @Provides Provides'tan daha özlüdür ve modül soyut bir sınıf olduğunda kullanılır.

Bir Modül Örneği

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

Bu örnekte, NetworkModule @Module ile açıklanan bir sınıftır. Retrofit ve OkHttpClient örneklerini oluşturan ve döndüren @Provides ile açıklanan iki yöntem içerir.

@Binds Kullanımı

Bir arayüz ve uygulaması olduğunda, uygulamayı arayüze bağlamak için @Binds kullanabilirsiniz. Bu, @Provides kullanmaktan daha özlüdür.

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

Bu örnekte, ApiModule @Module ile açıklanan soyut bir sınıftır. bindApiService yöntemi ApiServiceImpl ApiService bağlamak için @Binds ile açıklanmıştır.

Modüller sağladıkları işlevselliğe göre düzenlenebilir. Örneğin, ağ işlemleri, veritabanı işlemleri ve kullanıcı arayüzüyle ilgili bağımlılıklar için ayrı modülleriniz olabilir.

Örnek:

  • NetworkModule : Retrofit ve OkHttpClient gibi ağ ile ilgili bağımlılıkları sağlar.
  • DatabaseModule : RoomDatabase gibi veritabanıyla ilgili bağımlılıkları sağlar.
  • UIModule : ViewModel ve Presenter gibi UI ile ilgili bağımlılıkları sağlar.

Bileşenlere Modülleri Dahil Etme

Modüller, ihtiyaç duyan sınıflara bağımlılıklar sağlamak için bileşenlere dahil edilir. İşte nasıl kurabileceğiniz:

UygulamaBileşeni.java:

 @Singleton @Component(modules = {NetworkModule.class, DatabaseModule.class}) public interface ApplicationComponent { void inject(MyApplication application); }

Bu örnekte ApplicationComponent , uygulamaya bağımlılıklar sağlamak için NetworkModule ve DatabaseModule içerir.

2. Kapsamlar

Dagger 2'deki kapsamlar, bağımlılıkların yaşam döngüsünü tanımlayan açıklamalardır. Tek bir bağımlılık örneğinin belirli bir kapsam içinde oluşturulmasını ve paylaşılmasını sağlarlar. Bu, belleğin verimli bir şekilde yönetilmesine ve bağımlılıkların uygun yerlerde yeniden kullanılmasının sağlanmasına yardımcı olur.

  • Tekil Kapsam : Uygulamanın yaşam döngüsü boyunca tek bir bağımlılık örneğinin olmasını sağlar.
  • Etkinlik Kapsamı : Bir etkinliğin yaşam döngüsü içerisinde tek bir bağımlılık örneğinin olmasını sağlar.
  • Parça Kapsamı : Bir parçanın yaşam döngüsü içerisinde tek bir bağımlılık örneğinin olmasını sağlar.

1. Tekil Kapsam

Tanım : @Singleton kapsamı, bir bağımlılığın tek bir örneğinin oluşturulmasını ve uygulamanın tüm yaşam döngüsü boyunca paylaşılmasını sağlar.

Bu kapsam genellikle ağ istemcileri, veritabanı örnekleri veya paylaşılan tercihler gibi tüm uygulama genelinde paylaşılması gereken bağımlılıklar için kullanılır.

Örnek:

 @Singleton @Component(modules = {NetworkModule.class, DatabaseModule.class}) public interface ApplicationComponent { void inject(MyApplication application); }

Bu örnekte @Singleton ek açıklaması, NetworkModule ve DatabaseModule tarafından sağlanan Retrofit ve Database örneklerinin tekil olmasını ve tüm uygulama genelinde paylaşılmasını sağlar.

2. Faaliyet Kapsamı

Tanım : @ActivityScope (özel kapsam), bir bağımlılığın tek bir örneğinin bir aktivitenin yaşam döngüsü içerisinde oluşturulmasını ve paylaşılmasını sağlar.

Bu kapsam, bir etkinliğe özgü olan ve etkinlik her yeniden oluşturulduğunda yeniden oluşturulması gereken sunucular veya görünüm modelleri gibi bağımlılıklar için yararlıdır.

Örnek :

 @Scope @Retention(RetentionPolicy.RUNTIME) public @interface ActivityScope { } @ActivityScope @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); }

Bu örnekte, @ActivityScope açıklaması, ActivityModule tarafından sağlanan bağımlılıkların etkinliğin yaşam döngüsüne göre kapsamlandırılmasını sağlar.

3. Parça Kapsamı

Tanım : @FragmentScope (başka bir özel kapsam), bir bağımlılığın tek bir örneğinin bir parçanın yaşam döngüsü içinde oluşturulmasını ve paylaşılmasını sağlar.

Kullanım Durumu: Bu kapsam, parçaya özgü olan ve parça her yeniden oluşturulduğunda yeniden oluşturulması gereken bağımlılıklar (parçaya özgü sunucular veya görünüm modelleri gibi) için yararlıdır.

Örnek :

 @Scope @Retention(RetentionPolicy.RUNTIME) public @interface FragmentScope { } @FragmentScope @Component(dependencies = ActivityComponent.class, modules = FragmentModule.class) public interface FragmentComponent { void inject(MyFragment myFragment); }

Bu örnekte, @FragmentScope açıklaması, FragmentModule tarafından sağlanan bağımlılıkların parçanın yaşam döngüsüne göre kapsamlandırılmasını sağlar.

3. Bileşenler

Bileşen bağımlılıkları, bir bileşenin diğerine bağımlı olmasını sağlayarak bağımlılıkların yeniden kullanılmasını sağlar. İki ana bileşen bağımlılığı türü vardır:

  • Uygulama Bileşeni : Uygulamanın tamamında ihtiyaç duyulan bağımlılıkları sağlar.
  • Etkinlik Bileşeni : Belirli bir etkinlik içinde ihtiyaç duyulan bağımlılıkları sağlar.

1. Uygulama Bileşeni

Tanım : Uygulama Bileşeni, tüm uygulama boyunca ihtiyaç duyulan bağımlılıkları sağlar. Genellikle, bağımlılıkların uygulama genelinde paylaşıldığından emin olmak için @Singleton ile kapsamlandırılır.

Bu bileşen, ağ istemcileri, veritabanı örnekleri veya paylaşılan tercihler gibi küresel olarak kullanılabilir olması gereken bağımlılıklar için kullanılır.

Örnek :

 @Singleton @Component(modules = {NetworkModule.class, DatabaseModule.class}) public interface ApplicationComponent { void inject(MyApplication application); }

Bu örnekte ApplicationComponent , tüm uygulama genelinde paylaşılan Retrofit ve Database örneklerini sağlamaktan sorumludur.

2. Etkinlik Bileşeni

Tanım : Etkinlik Bileşeni, belirli bir etkinlik içinde ihtiyaç duyulan bağımlılıkları sağlar. Genellikle, etkinlik her yeniden oluşturulduğunda bağımlılıkların yeniden oluşturulmasını sağlamak için @ActivityScope gibi özel bir kapsamla kapsamlandırılır.

Bu bileşen, sunucular veya görünüm modelleri gibi bir etkinliğe özgü bağımlılıklar için kullanılır.

Örnek :

 @ActivityScope @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); }

Bu örnekte ActivityComponent , ApplicationComponent bağımlıdır ve MainActivity özgü bağımlılıklar sağlar.

4. Bileşen Bağımlılıkları

Bileşen bağımlılıkları, bir bileşenin diğerine bağımlı olmasını sağlayarak bağımlılıkların yeniden kullanılmasını sağlar. İki ana bileşen bağımlılığı türü vardır:

  • Alt Bileşenler : Bir alt bileşen, başka bir bileşenin çocuğudur ve üst bileşeninin bağımlılıklarına erişebilir.
  • Bağımlılık Niteliği : Bu, bir bileşenin alt bileşen olmadan başka bir bileşene bağımlı olmasını sağlar.

1. Alt bileşenler:

Bir alt bileşen, başka bir bileşenin çocuğudur ve üst bileşeninin bağımlılıklarına erişebilir. Alt bileşenler üst bileşen içinde tanımlanır ve kapsamını devralabilir.

Örnek :

 @ActivityScope @Subcomponent(modules = ActivityModule.class) public interface ActivitySubcomponent { void inject(MainActivity mainActivity); }

Bu örnekte ActivitySubcomponent , ana bileşenin bir alt bileşenidir ve onun bağımlılıklarına erişebilir.

2. Bağımlılık Niteliği

Bu, bir bileşenin alt bileşen olmadan başka bir bileşene bağımlı olmasını sağlar. Bağımlı bileşen, ana bileşen tarafından sağlanan bağımlılıklara erişebilir.

Örnek :

 @ActivityScope @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); }

Bu örnekte ActivityComponent , ApplicationComponent bağımlıdır ve onun bağımlılıklarına erişebilir.

5. Çalışma Zamanı Bağlamaları

Dagger 2'deki çalışma zamanı bağlamaları, ihtiyaç duyuldukları bağlama göre çalışma zamanında oluşturulan ve yönetilen bağımlılıkların sağlanması anlamına gelir.

  • Uygulama Bağlamı : Uygulama süresince yaşaması gereken bağımlılıklar için kullanılır.
  • Etkinlik Bağlamı : Bir etkinlik kadar uzun süre yaşaması gereken bağımlılıklar için kullanılır.

1. Uygulama Bağlamı

Tanım : Uygulama bağlamı, tüm uygulamanın yaşam döngüsüne bağlı bir bağlamdır. Uygulamanın kendisi kadar uzun süre yaşaması gereken bağımlılıklar için kullanılır.

Tüm uygulama genelinde paylaşılan ve her etkinlik veya parça için yeniden oluşturulması gerekmeyen bağımlılıklar. Örnekler arasında ağ istemcileri, veritabanı örnekleri ve paylaşılan tercihler bulunur.

Örnek :

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

Bu örnekte, AppModule uygulama bağlamını tekil bir bağımlılık olarak sağlar. provideApplicationContext yöntemi, sağlanan bağlamın uygulamanın yaşam döngüsüne bağlı olduğundan emin olur.

2. Etkinlik Bağlamı

Tanım : Etkinlik bağlamı, belirli bir etkinliğin yaşam döngüsüne bağlı bir bağlamdır. Etkinliğin kendisi kadar uzun süre yaşaması gereken bağımlılıklar için kullanılır.

Bir aktiviteye özgü olan ve aktivite her yeniden oluşturulduğunda yeniden oluşturulması gereken bağımlılıklar. Örnekler arasında görünüm modelleri, sunucular ve kullanıcı arayüzüyle ilgili bağımlılıklar bulunur.

Örnek :

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

Bu örnekte, ActivityModule etkinlik bağlamını kapsamlı bir bağımlılık olarak sağlar. provideActivityContext yöntemi, sağlanan bağlamın etkinliğin yaşam döngüsüne bağlı olduğundan emin olur.

Bileşenlerde Çalışma Zamanı Bağlamalarını Kullanma

Bu çalışma zamanı bağlamalarını kullanmak için bileşenlerinize ilgili modülleri eklemeniz gerekir:

Uygulama Bileşeni :

 @Singleton @Component(modules = {AppModule.class, NetworkModule.class}) public interface ApplicationComponent { void inject(MyApplication application); Context getApplicationContext(); }

Etkinlik Bileşeni :

 @ActivityScope @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); Context getActivityContext(); }

Bağlamları Enjekte Etmek

Bileşenlerinizi ve modüllerinizi kurduktan sonra, ihtiyaç duyduğunuzda bağlamları sınıflarınıza ekleyebilirsiniz.

Bir Aktivitede Örnek :

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

Bu örnekte, MainActivity hem etkinlik bağlamını hem de uygulama bağlamını bağımlılık enjeksiyonu yoluyla alır. Bu, etkinliğin bağımlılıkların belirli ihtiyaçlarına göre uygun bağlamı kullanmasına olanak tanır.

Örnek: Android Uygulamasında Dagger 2 Kullanımı

Dagger 2 Kurulumu

Dagger 2'yi projenizde kullanmak için build.gradle dosyanıza aşağıdaki bağımlılıkları eklemeniz gerekiyor:

 dependencies { implementation 'com.google.dagger:dagger:2.x' annotationProcessor 'com.google.dagger:dagger-compiler:2.x' }

2.x Dagger 2'nin son sürümüyle değiştirin.

Adım 1: Bir Modül Tanımlayın

Bağımlılıkları sağlamak için bir modül oluşturun. Örneğin, Retrofit örneği sağlamak için bir NetworkModule :

 @Module public class NetworkModule { @Provides @Singleton Retrofit provideRetrofit() { return new Retrofit.Builder() .baseUrl("https://api.example.com") .addConverterFactory(GsonConverterFactory.create()) .build(); } }

Adım 2: Bir Bileşeni Tanımlayın

Modül ile bağımlılıklara ihtiyaç duyan sınıflar arasında köprü kuracak bir bileşen oluşturun:

 @Singleton @Component(modules = {NetworkModule.class}) public interface ApplicationComponent { void inject(MyApplication application); }

Adım 3: Bağımlılıkları Enjekte Edin

Bileşeni, sınıflarınıza bağımlılıklar enjekte etmek için kullanın. Örneğin, Application sınıfınızda:

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

Adım 4: Enjekte Edilen Bağımlılıkları Kullanın

Artık enjekte edilen bağımlılıkları sınıflarınızda kullanabilirsiniz. Örneğin, bir 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 // ... } }

Çözüm

Konuyu özetleyelim:

  • DI'ın temel amacı, bağımlılıkları yönetmeyi kolaylaştırarak, bağlantıları gevşetmektir.
  • DI kullanarak kod esnekliğini artırabilir ve test sürecini basitleştirebilirsiniz.
  • DI, senaryoya göre farklı uygulamaları olan karmaşık bir konudur.
  • DI'ın farklı dillerde kullanımı, onunla nasıl çalışacağınızı etkileyebilecek özelliklere sahiptir.
  • Dagger 2, bağımlılıkların oluşturulması ve sağlanması sürecini otomatikleştirerek, kalıp kodları azaltır ve sürdürülebilirliği artırır.
  • Dagger 2, uygulama çalıştırılmadan önce tüm bağımlılıkların karşılandığından emin olarak derleme zamanı güvenliği sağlar.
  • Dagger 2, derleme zamanında kod üreterek yansıma tabanlı çözümlerle ilişkili performans yükünden kaçınır.