Dependency Injection (DI) là một mẫu thiết kế được sử dụng để triển khai Inversion of Control (IoC) trong đó quyền kiểm soát việc tạo và quản lý các phụ thuộc được chuyển từ ứng dụng sang một thực thể bên ngoài. Điều này giúp tạo ra mã có thể mô-đun hóa, có thể kiểm tra và bảo trì được nhiều hơn. Đây là một kỹ thuật trong đó trách nhiệm tạo đối tượng được chuyển sang các phần khác của mã. Điều này thúc đẩy sự kết hợp lỏng lẻo, làm cho mã có tính mô-đun hóa và dễ quản lý hơn.
Các lớp thường cần tham chiếu đến các lớp khác để hoạt động bình thường. Ví dụ, hãy xem xét một lớp Library
yêu cầu một lớp Book
. Các lớp cần thiết này được gọi là các phụ thuộc. Lớp Library
phụ thuộc vào việc có một thể hiện của lớp Book
để hoạt động.
Có ba cách chính để một lớp có thể lấy được các đối tượng cần thiết:
Library
sẽ tạo và khởi tạo phiên bản riêng của lớp Book
.Context
getters và getSystemService()
, hoạt động theo cách này.Library
sẽ nhận một thể hiện Book
làm tham số.Tùy chọn thứ ba là dependency injection! Với DI, bạn cung cấp các dependency của một lớp thay vì để chính thể hiện lớp đó lấy chúng.
Nếu không có DI, Library
tạo ra sự phụ thuộc Book
của riêng nó có thể trông như thế này:
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(); } }
Đây không phải là ví dụ về DI vì lớp Library
xây dựng Book
của riêng nó. Điều này có thể gây ra vấn đề vì:
Library
và Book
được liên kết chặt chẽ. Một thể hiện của Library
sử dụng một loại Book
, khiến việc sử dụng các lớp con hoặc triển khai thay thế trở nên khó khăn.Book
khiến việc kiểm thử trở nên khó khăn hơn. Library
sử dụng một phiên bản thực của Book
, ngăn chặn việc sử dụng các bản sao thử nghiệm để sửa đổi Book
cho các trường hợp thử nghiệm khác nhau. Với DI, thay vì mỗi phiên bản của Library
xây dựng đối tượng Book
riêng, nó sẽ nhận một đối tượng Book
làm tham số trong hàm tạo của nó:
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(); }
Hàm chính sử dụng Library
. Vì Library
phụ thuộc vào Book
, ứng dụng tạo một thể hiện của Book
và sau đó sử dụng nó để xây dựng một thể hiện của Library
. Lợi ích của phương pháp dựa trên DI này là:
Library
: Bạn có thể truyền các triển khai khác nhau của Book
vào Library
. Ví dụ, bạn có thể định nghĩa một lớp con mới của Book
có tên là EBook
mà bạn muốn Library
sử dụng. Với DI, bạn chỉ cần truyền một thể hiện của EBook
vào Library
và nó hoạt động mà không cần bất kỳ thay đổi nào nữa.Library
dễ dàng: Bạn có thể truyền các bản sao thử nghiệm để kiểm tra các tình huống khác nhau. Hãy xem xét một kịch bản trong đó lớp NotificationService
dựa vào lớp Notification
. Nếu không có DI, NotificationService
sẽ trực tiếp tạo một thể hiện của Notification
, khiến việc sử dụng các loại thông báo khác nhau hoặc kiểm tra dịch vụ bằng nhiều triển khai thông báo khác nhau trở nên khó khăn.
Để minh họa DI, chúng ta hãy tái cấu trúc ví dụ này:
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(); } }
Bây giờ, NotificationService
phụ thuộc vào giao diện Notification
chứ không phải một lớp cụ thể. Điều này cho phép các triển khai Notification
khác nhau có thể được sử dụng thay thế cho nhau. Bạn có thể thiết lập triển khai bạn muốn sử dụng thông qua phương thức sendNotification
:
NotificationService service = new NotificationService(); service.sendNotification(new EmailNotification()); service.sendNotification(new SMSNotification());
Có ba loại DI chính:
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. Field Injection (hoặc Setter Injection) : Một số lớp khung Android, chẳng hạn như các hoạt động và các đoạn mã, được hệ thống khởi tạo, do đó không thể khởi tạo constructor injection. Với field injection, các dependency được khởi tạo sau khi lớp được tạo.
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. Phương thức Injection : Các phụ thuộc được cung cấp thông qua các phương thức, thường sử dụng chú thích @Inject
.
Trong ví dụ trước, bạn đã tạo, cung cấp và quản lý thủ công các phụ thuộc của các lớp khác nhau mà không sử dụng thư viện. Cách tiếp cận này được gọi là tiêm phụ thuộc thủ công. Mặc dù nó hoạt động với các trường hợp đơn giản, nhưng nó trở nên cồng kềnh khi số lượng phụ thuộc và lớp tăng lên. Tiêm phụ thuộc thủ công có một số nhược điểm:
Thư viện có thể tự động hóa quy trình này bằng cách tạo và cung cấp các phụ thuộc cho bạn. Các thư viện này được chia thành hai loại:
Dagger là một thư viện dependency injection phổ biến cho Java, Kotlin và Android, được Google duy trì. Dagger đơn giản hóa DI trong ứng dụng của bạn bằng cách tạo và quản lý biểu đồ dependency cho bạn. Nó cung cấp các dependency hoàn toàn tĩnh, thời gian biên dịch, giải quyết nhiều vấn đề về phát triển và hiệu suất liên quan đến các giải pháp dựa trên phản chiếu như Guice.
Các khung này kết nối các phụ thuộc khi chạy:
Các khung này tạo ra mã để kết nối các phụ thuộc tại thời điểm biên dịch:
Một giải pháp thay thế cho dependency injection là mẫu service locator. Mẫu thiết kế này cũng giúp tách các lớp khỏi các dependency cụ thể của chúng. Bạn tạo một lớp được gọi là service locator để tạo và lưu trữ các dependency, cung cấp chúng theo yêu cầu.
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() }
Mẫu service locator khác với dependency injection ở cách dependency được sử dụng. Với mẫu service locator, các lớp yêu cầu các dependency mà chúng cần; với dependency injection, ứng dụng chủ động cung cấp các đối tượng cần thiết.
Dagger 2 là một DI framework phổ biến cho Android. Nó sử dụng thế hệ mã thời gian biên dịch và được biết đến với hiệu suất cao. Dagger 2 đơn giản hóa quá trình tiêm phụ thuộc bằng cách tạo mã cần thiết để xử lý các phụ thuộc, giảm mẫu và cải thiện hiệu quả.
Dagger 2 là một thư viện dựa trên chú thích để tiêm phụ thuộc trong Android. Sau đây là các chú thích chính và mục đích của chúng:
ApiClient
cho Retrofit.@Module
và @Inject
. Giao diện này chứa tất cả các module và cung cấp trình xây dựng cho ứng dụng.@Provides
nhưng ngắn gọn hơn. Dagger có thể tạo biểu đồ phụ thuộc cho dự án của bạn, cho phép nó xác định nơi lấy các phụ thuộc khi cần. Để bật tính năng này, bạn cần tạo một giao diện và chú thích nó bằng @Component
.
Trong giao diện @Component
, bạn định nghĩa các phương thức trả về các thể hiện của các lớp bạn cần (ví dụ: BookRepository
). Chú thích @Component
hướng dẫn Dagger tạo một vùng chứa với tất cả các phụ thuộc cần thiết để đáp ứng các kiểu mà nó hiển thị. Vùng chứa này được gọi là thành phần Dagger và nó chứa một biểu đồ các đối tượng mà Dagger biết cách cung cấp cùng với các phụ thuộc của chúng.
Hãy cùng xem xét một ví dụ liên quan đến LibraryRepository
:
@Inject
vào hàm tạo LibraryRepository
để Dagger biết cách tạo một thể hiện của LibraryRepository
. public class LibraryRepository { private final LocalLibraryDataSource localDataSource; private final RemoteLibraryDataSource remoteDataSource; @Inject public LibraryRepository(LocalLibraryDataSource localDataSource, RemoteLibraryDataSource remoteDataSource) { this.localDataSource = localDataSource; this.remoteDataSource = remoteDataSource; } }
2. Chú thích các phụ thuộc : Tương tự như vậy, hãy chú thích các hàm tạo của các phụ thuộc ( LocalLibraryDataSource
và RemoteLibraryDataSource
) để Dagger biết cách tạo chúng.
public class LocalLibraryDataSource { @Inject public LocalLibraryDataSource() { // Initialization code } } public class RemoteLibraryDataSource { private final LibraryService libraryService; @Inject public RemoteLibraryDataSource(LibraryService libraryService) { this.libraryService = libraryService; } }
3. Xác định Thành phần : Tạo một giao diện được chú thích bằng @Component
để xác định biểu đồ phụ thuộc.
@Component public interface ApplicationComponent { LibraryRepository getLibraryRepository(); }
Khi bạn xây dựng dự án, Dagger sẽ tạo ra một triển khai giao diện ApplicationComponent
cho bạn, thường được đặt tên là DaggerApplicationComponent
.
Bây giờ bạn có thể sử dụng thành phần được tạo để lấy các phiên bản của lớp với các phụ thuộc được tự động đưa vào:
public class MainApplication extends Application { private ApplicationComponent applicationComponent; @Override public void onCreate() { super.onCreate(); applicationComponent = DaggerApplicationComponent.create(); } public ApplicationComponent getApplicationComponent() { return applicationComponent; } }
Trong hoạt động hoặc đoạn mã của bạn, bạn có thể truy xuất phiên bản LibraryRepository
:
public class MainActivity extends AppCompatActivity { @Inject LibraryRepository libraryRepository; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ((MainApplication) getApplication()).getApplicationComponent().inject(this); // Use the injected libraryRepository } }
1. Các mô-đun
∘ Các khái niệm chính của Mô-đun
∘ Bao gồm các mô-đun trong các thành phần
2. Phạm vi
3. Thành phần
4. Phụ thuộc thành phần
5. Liên kết thời gian chạy
Module trong Dagger 2 là các lớp được chú thích bằng @Module
cung cấp các phụ thuộc cho các thành phần. Chúng chứa các phương thức được chú thích bằng @Provides
hoặc @Binds
để chỉ định cách tạo và cung cấp các phụ thuộc. Module rất cần thiết để tổ chức và quản lý việc tạo các đối tượng mà ứng dụng của bạn cần.
@Provides
và được sử dụng khi mô-đun là một lớp trừu tượng.Ví dụ về một mô-đun
@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(); } }
Trong ví dụ này, NetworkModule
là một lớp được chú thích bằng @Module
. Nó chứa hai phương thức được chú thích bằng @Provides
để tạo và trả về các thể hiện của Retrofit
và OkHttpClient
.
Sử dụng @Binds
Khi bạn có một giao diện và triển khai của nó, bạn có thể sử dụng @Binds
để liên kết triển khai với giao diện. Điều này ngắn gọn hơn so với sử dụng @Provides
.
public interface ApiService { void fetchData(); } public class ApiServiceImpl implements ApiService { @Override public void fetchData() { // Implementation } } @Module public abstract class ApiModule { @Binds abstract ApiService bindApiService(ApiServiceImpl apiServiceImpl); }
Trong ví dụ này, ApiModule
là một lớp trừu tượng được chú thích bằng @Module
. Phương thức bindApiService
được chú thích bằng @Binds
để liên kết ApiServiceImpl
với ApiService
.
Các mô-đun có thể được sắp xếp dựa trên chức năng mà chúng cung cấp. Ví dụ, bạn có thể có các mô-đun riêng cho hoạt động mạng, hoạt động cơ sở dữ liệu và các phụ thuộc liên quan đến UI.
Ví dụ:
Retrofit
và OkHttpClient
.RoomDatabase
.ViewModel
và Presenter
.Các mô-đun được bao gồm trong các thành phần để cung cấp các phụ thuộc cho các lớp cần chúng. Sau đây là cách bạn có thể thiết lập:
ApplicationComponent.java:
@Singleton @Component(modules = {NetworkModule.class, DatabaseModule.class}) public interface ApplicationComponent { void inject(MyApplication application); }
Trong ví dụ này, ApplicationComponent
bao gồm NetworkModule
và DatabaseModule
để cung cấp các phụ thuộc cho ứng dụng.
Phạm vi trong Dagger 2 là các chú thích xác định vòng đời của các phụ thuộc. Chúng đảm bảo rằng một phiên bản duy nhất của một phụ thuộc được tạo và chia sẻ trong một phạm vi được chỉ định. Điều này giúp quản lý bộ nhớ hiệu quả và đảm bảo rằng các phụ thuộc được sử dụng lại khi thích hợp.
1. Phạm vi Singleton
Định nghĩa : Phạm vi @Singleton
đảm bảo rằng một phiên bản duy nhất của sự phụ thuộc được tạo và chia sẻ trong toàn bộ vòng đời của ứng dụng.
Phạm vi này thường được sử dụng cho các phụ thuộc cần được chia sẻ trên toàn bộ ứng dụng, chẳng hạn như máy khách mạng, phiên bản cơ sở dữ liệu hoặc tùy chọn chia sẻ.
Ví dụ:
@Singleton @Component(modules = {NetworkModule.class, DatabaseModule.class}) public interface ApplicationComponent { void inject(MyApplication application); }
Trong ví dụ này, chú thích @Singleton
đảm bảo rằng các phiên bản Retrofit
và Database
do NetworkModule
và DatabaseModule
cung cấp là các phiên bản đơn lẻ và được chia sẻ trên toàn bộ ứng dụng.
2. Phạm vi hoạt động
Định nghĩa : @ActivityScope
(phạm vi tùy chỉnh) đảm bảo rằng một phiên bản duy nhất của sự phụ thuộc được tạo và chia sẻ trong vòng đời của một hoạt động.
Phạm vi này hữu ích cho các phụ thuộc cụ thể đối với một hoạt động và cần được tạo lại mỗi khi hoạt động được tạo lại, chẳng hạn như trình bày hoặc mô hình xem.
Ví dụ :
@Scope @Retention(RetentionPolicy.RUNTIME) public @interface ActivityScope { } @ActivityScope @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); }
Trong ví dụ này, chú thích @ActivityScope
đảm bảo rằng các phụ thuộc do ActivityModule
cung cấp sẽ nằm trong phạm vi vòng đời của hoạt động.
3. Phạm vi phân đoạn
Định nghĩa : @FragmentScope
(một phạm vi tùy chỉnh khác) đảm bảo rằng một phiên bản duy nhất của sự phụ thuộc được tạo và chia sẻ trong vòng đời của một đoạn mã.
Trường hợp sử dụng: Phạm vi này hữu ích cho các phụ thuộc cụ thể đối với một phân đoạn và cần được tạo lại mỗi khi phân đoạn được tạo lại, chẳng hạn như trình bày cụ thể cho phân đoạn hoặc mô hình xem.
Ví dụ :
@Scope @Retention(RetentionPolicy.RUNTIME) public @interface FragmentScope { } @FragmentScope @Component(dependencies = ActivityComponent.class, modules = FragmentModule.class) public interface FragmentComponent { void inject(MyFragment myFragment); }
Trong ví dụ này, chú thích @FragmentScope
đảm bảo rằng các phụ thuộc do FragmentModule
cung cấp sẽ nằm trong phạm vi vòng đời của đoạn mã.
Sự phụ thuộc thành phần cho phép một thành phần phụ thuộc vào thành phần khác, cho phép tái sử dụng các phụ thuộc. Có hai loại phụ thuộc thành phần chính:
1. Thành phần ứng dụng
Định nghĩa : Thành phần ứng dụng cung cấp các phụ thuộc cần thiết trong toàn bộ ứng dụng. Nó thường được giới hạn trong @Singleton
để đảm bảo rằng các phụ thuộc được chia sẻ trên toàn bộ ứng dụng.
Thành phần này được sử dụng cho các phụ thuộc cần có sẵn trên toàn cầu, chẳng hạn như máy khách mạng, phiên bản cơ sở dữ liệu hoặc tùy chọn chia sẻ.
Ví dụ :
@Singleton @Component(modules = {NetworkModule.class, DatabaseModule.class}) public interface ApplicationComponent { void inject(MyApplication application); }
Trong ví dụ này, ApplicationComponent
chịu trách nhiệm cung cấp các phiên bản Retrofit
và Database
được chia sẻ trên toàn bộ ứng dụng.
2. Thành phần hoạt động
Định nghĩa : Thành phần Hoạt động cung cấp các phụ thuộc cần thiết trong một hoạt động cụ thể. Nó thường được định phạm vi với phạm vi tùy chỉnh, chẳng hạn như @ActivityScope
, để đảm bảo rằng các phụ thuộc được tạo lại mỗi khi hoạt động được tạo lại.
Thành phần này được sử dụng cho các phụ thuộc cụ thể cho một hoạt động, chẳng hạn như người trình bày hoặc mô hình xem.
Ví dụ :
@ActivityScope @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); }
Trong ví dụ này, ActivityComponent
phụ thuộc vào ApplicationComponent
và cung cấp các phụ thuộc cụ thể cho MainActivity
.
Sự phụ thuộc thành phần cho phép một thành phần phụ thuộc vào thành phần khác, cho phép tái sử dụng các phụ thuộc. Có hai loại phụ thuộc thành phần chính:
1. Các thành phần phụ:
Một thành phần con là thành phần con của một thành phần khác và có thể truy cập vào các phụ thuộc của thành phần cha. Các thành phần con được định nghĩa trong thành phần cha và có thể kế thừa phạm vi của thành phần cha.
Ví dụ :
@ActivityScope @Subcomponent(modules = ActivityModule.class) public interface ActivitySubcomponent { void inject(MainActivity mainActivity); }
Trong ví dụ này, ActivitySubcomponent
là một thành phần con của thành phần cha và có thể truy cập vào các phần phụ thuộc của nó.
2. Thuộc tính phụ thuộc
Điều này cho phép một thành phần phụ thuộc vào một thành phần khác mà không phải là thành phần phụ. Thành phần phụ thuộc có thể truy cập vào các phụ thuộc do thành phần cha cung cấp.
Ví dụ :
@ActivityScope @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); }
Trong ví dụ này, ActivityComponent
phụ thuộc vào ApplicationComponent
và có thể truy cập vào các phần phụ thuộc của nó.
Liên kết thời gian chạy trong Dagger 2 đề cập đến việc cung cấp các phụ thuộc được tạo và quản lý tại thời gian chạy, dựa trên bối cảnh cần đến chúng.
1. Bối cảnh ứng dụng
Định nghĩa : Ngữ cảnh ứng dụng là ngữ cảnh gắn liền với vòng đời của toàn bộ ứng dụng. Ngữ cảnh này được sử dụng cho các phụ thuộc cần tồn tại lâu dài như chính ứng dụng.
Các phụ thuộc được chia sẻ trên toàn bộ ứng dụng và không cần phải tạo lại cho từng hoạt động hoặc đoạn. Ví dụ bao gồm máy khách mạng, phiên bản cơ sở dữ liệu và tùy chọn chia sẻ.
Ví dụ :
@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(); } }
Trong ví dụ này, AppModule
cung cấp ngữ cảnh ứng dụng dưới dạng phụ thuộc singleton. Phương thức provideApplicationContext
đảm bảo rằng ngữ cảnh được cung cấp được gắn với vòng đời của ứng dụng.
2. Bối cảnh hoạt động
Định nghĩa : Ngữ cảnh hoạt động là ngữ cảnh gắn liền với vòng đời của một hoạt động cụ thể. Ngữ cảnh này được sử dụng cho các phụ thuộc cần tồn tại lâu dài như chính hoạt động đó.
Các phụ thuộc cụ thể cho một hoạt động và cần được tạo lại mỗi lần hoạt động được tạo lại. Ví dụ bao gồm mô hình xem, trình bày và các phụ thuộc liên quan đến UI.
Ví dụ :
@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; } }
Trong ví dụ này, ActivityModule
cung cấp ngữ cảnh hoạt động dưới dạng phụ thuộc có phạm vi. Phương thức provideActivityContext
đảm bảo rằng ngữ cảnh được cung cấp được gắn với vòng đời của hoạt động.
Để sử dụng các ràng buộc thời gian chạy này, bạn cần đưa các mô-đun tương ứng vào các thành phần của mình:
Thành phần ứng dụng :
@Singleton @Component(modules = {AppModule.class, NetworkModule.class}) public interface ApplicationComponent { void inject(MyApplication application); Context getApplicationContext(); }
Thành phần hoạt động :
@ActivityScope @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); Context getActivityContext(); }
Tiêm ngữ cảnh
Sau khi thiết lập các thành phần và mô-đun, bạn có thể đưa ngữ cảnh vào các lớp khi cần.
Ví dụ trong một Hoạt động :
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); } }
Trong ví dụ này, MainActivity
nhận được cả ngữ cảnh hoạt động và ngữ cảnh ứng dụng thông qua dependency injection. Điều này cho phép hoạt động sử dụng ngữ cảnh phù hợp dựa trên nhu cầu cụ thể của các phụ thuộc.
Để sử dụng Dagger 2 trong dự án của bạn, bạn cần thêm các phụ thuộc sau vào tệp build.gradle
:
dependencies { implementation 'com.google.dagger:dagger:2.x' annotationProcessor 'com.google.dagger:dagger-compiler:2.x' }
Thay thế 2.x
bằng phiên bản mới nhất của Dagger 2.
Tạo một mô-đun để cung cấp các phụ thuộc. Ví dụ: một NetworkModule
để cung cấp một thể hiện Retrofit
:
@Module public class NetworkModule { @Provides @Singleton Retrofit provideRetrofit() { return new Retrofit.Builder() .baseUrl("https://api.example.com") .addConverterFactory(GsonConverterFactory.create()) .build(); } }
Tạo một thành phần để kết nối mô-đun và các lớp cần sự phụ thuộc:
@Singleton @Component(modules = {NetworkModule.class}) public interface ApplicationComponent { void inject(MyApplication application); }
Sử dụng thành phần để đưa các phụ thuộc vào các lớp của bạn. Ví dụ, trong lớp Application
của bạn:
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; } }
Bây giờ bạn có thể sử dụng các dependency được inject trong các lớp của mình. Ví dụ, trong một 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 // ... } }
Chúng ta hãy tóm tắt chủ đề này: