Ở bài viết này sẽ nói về kế hoạch phát triển Dagger 2 của Google trong năm 2020.
Nội dung bài viết được lấy từ: Gitconnected
Trước đây, để tích hợp Dagger vào ứng dụng rất phức tạp. Để giảm thiểu cũng như khắc phục vấn đề này, tại Android Dev Summit 2019, Manuel Vivo và Daniel Santiago đã có 1 cuộc nói chuyện về DI và kế hoạch cho Dagger 2
trong thời gian tới. Chi tiết có thể xem ở video. Hoặc bạn có thể theo dõi bài viết này. Lưu ý đây chỉ là kế hoạch sắp tới thôi nhé.
Google đã nói rõ:
Use Dagger 2 for your Medium / Large Android Project
I. Dagger 2 sẽ hoạt động tốt hơn với Kotlin
1. Hỗ trợ @Module
annotation Object class
- Hiện tại chúng ta cần có
JvmStatic
:
1 2 3 4 5 6 7 8 9 | <span class="token annotation builtin">@Module</span> <span class="token keyword">object</span> DatabaseModule <span class="token punctuation">{</span> <span class="token annotation builtin">@Provides</span> <span class="token annotation builtin">@JvmStatic</span> <span class="token keyword">fun</span> <span class="token function">provideDB</span><span class="token punctuation">(</span>ctx<span class="token operator">:</span> Context<span class="token punctuation">)</span><span class="token operator">:</span> AppDatabase <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- Kế hoạch là sẽ loại bỏ
JvmStatic
:
1 2 3 4 5 6 7 8 | <span class="token annotation builtin">@Module</span> <span class="token keyword">object</span> DatabaseModule <span class="token punctuation">{</span> <span class="token annotation builtin">@Provides</span> <span class="token keyword">fun</span> <span class="token function">provideDB</span><span class="token punctuation">(</span>ctx<span class="token operator">:</span> Context<span class="token punctuation">)</span><span class="token operator">:</span> AppDatabase <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
2. Nhận biết @Qualifier
annotation
- Hiện tại chúng ta cần có 1 trường
field
cho Qualifier name:
1 2 3 4 5 6 | <span class="token keyword">class</span> ProfileActivity<span class="token operator">:</span> <span class="token function">AppCompatActivity</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token annotation builtin">@Inject</span> <span class="token annotation builtin">@field:Username</span> <span class="token keyword">lateinit</span> <span class="token keyword">var</span> username<span class="token operator">:</span> String <span class="token punctuation">}</span> |
- Kế hoạch là loại bỏ
field
:
1 2 3 4 5 6 | <span class="token keyword">class</span> ProfileActivity<span class="token operator">:</span> <span class="token function">AppCompatActivity</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token annotation builtin">@Inject</span> <span class="token annotation builtin">@Username</span> <span class="token keyword">lateinit</span> <span class="token keyword">var</span> username<span class="token operator">:</span> String <span class="token punctuation">}</span> |
3. Nhận biết Kotlin Wildcards
- Hiện tại cần có
@JvmSupressWildcards
khi sử dụngKotlin wildcard
:
1 2 3 4 5 6 7 8 | <span class="token annotation builtin">@Module</span> <span class="token keyword">class</span> ConfigurationModule <span class="token punctuation">{</span> <span class="token annotation builtin">@Provides</span> <span class="token keyword">fun</span> <span class="token function">provideOptions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> List<span class="token operator"><</span><span class="token annotation builtin">@JvmSupressWildcards</span> String<span class="token operator">></span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- Kế hoạch là loại bỏ nó:
1 2 3 4 5 6 7 8 | <span class="token annotation builtin">@Module</span> <span class="token keyword">class</span> ConfigurationModule <span class="token punctuation">{</span> <span class="token annotation builtin">@Provides</span> <span class="token keyword">fun</span> <span class="token function">provideOptions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> List<span class="token operator"><</span>String<span class="token operator">></span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
II. Đơn giản sử dụng Dagger 2
1. Jnjection
- Hiện tại, cách duy nhất đển inject
Dagger 2
vào Activity là get component và self injection 1 cách tường minh như bên dưới:
1 2 3 4 5 6 7 8 9 | <span class="token keyword">class</span> PlayingActivity<span class="token operator">:</span> <span class="token function">AppCompactActivity</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token annotation builtin">@Inject</span> <span class="token keyword">lateinit</span> <span class="token keyword">var</span> player<span class="token operator">:</span> Player <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">onCreate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">val</span> appComponent <span class="token operator">=</span> <span class="token punctuation">(</span>applicationContext <span class="token keyword">as</span> MyApp<span class="token punctuation">)</span><span class="token punctuation">.</span>appComponent appComponent<span class="token punctuation">.</span><span class="token function">inject</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
hoặc chúng ta cần kế thừa Dagger 2 Activity class:
1 2 3 4 5 | <span class="token keyword">class</span> PlayingActivity<span class="token operator">:</span> <span class="token function">DaggerAppCompactActivity</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token annotation builtin">@Inject</span> <span class="token keyword">lateinit</span> <span class="token keyword">var</span> player<span class="token operator">:</span> Player <span class="token punctuation">}</span> |
- Với kế hoạch tiếp theo của Google là sử dụng
@EntryPoint
để đơn giản hóa việc inject:
1 2 3 4 5 6 | <span class="token annotation builtin">@EntryPoint</span> <span class="token keyword">class</span> PlayingActivity<span class="token operator">:</span> <span class="token function">AppCompactActivity</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token annotation builtin">@Inject</span> <span class="token keyword">lateinit</span> <span class="token keyword">var</span> player<span class="token operator">:</span> Player <span class="token punctuation">}</span> |
Ngoài ra, còn support cho việc inject ViewModel
1 2 3 4 5 6 | <span class="token annotation builtin">@EntryPoint</span> <span class="token keyword">class</span> PlayingActivity<span class="token operator">:</span> <span class="token function">AppCompactActivity</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token annotation builtin">@Inject</span> <span class="token keyword">lateinit</span> <span class="token keyword">var</span> playbackViewModel<span class="token operator">:</span> PlaybackViewModel <span class="token punctuation">}</span> |
2. Predefined Components
Để sử dụng Dagger 2
chúng ta cần define 1 AppComponent
và là kiểu Singleton
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token annotation builtin">@Singleton</span> <span class="token annotation builtin">@Component</span><span class="token punctuation">(</span>modules <span class="token operator">=</span> <span class="token punctuation">[</span>DatabaseModule<span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">]</span> <span class="token keyword">interface</span> AppComponent <span class="token punctuation">{</span> <span class="token keyword">fun</span> <span class="token function">injectActivity</span><span class="token punctuation">(</span>activity<span class="token operator">:</span> PlayingActivity<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token annotation builtin">@Module</span> <span class="token keyword">object</span> DatabaseModule <span class="token punctuation">{</span> <span class="token annotation builtin">@Provides</span> <span class="token annotation builtin">@Singleton</span> <span class="token keyword">fun</span> <span class="token function">provideDatabase</span> <span class="token punctuation">(</span><span class="token operator">..</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token operator">:</span> Music Database <span class="token punctuation">{</span> <span class="token comment">// ... </span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- Google sẽ thay thế việc define
AppComponent
bằng việc sử dụng@InstallIn
annotation ở bên ngoài vớiSingletonComponent
:
1 2 3 4 5 6 7 8 9 10 | <span class="token annotation builtin">@Module</span> <span class="token annotation builtin">@InstallIn</span><span class="token punctuation">(</span>SingletonComponent<span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span> <span class="token keyword">object</span> DatabaseModule <span class="token punctuation">{</span> <span class="token annotation builtin">@Provides</span> <span class="token annotation builtin">@Singleton</span> <span class="token keyword">fun</span> <span class="token function">provideDatabase</span> <span class="token punctuation">(</span><span class="token operator">..</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token operator">:</span> Music Database <span class="token punctuation">{</span> <span class="token comment">// ... </span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Không chỉ cung cấp SingletonComponent
mà còn có ActivityComponent
, FragmentComponent
, ServiceComponent
Việc này giúp chúng ta tránh được việc tạo nhiều boilerplate code.
Việc thay đổi này của Dagger 2
không ảnh hưởng đến cách sử dụng trước đó, nên chúng ta không cần phải quan tâm rằng nó có ảnh hưởng tới những phát triển trước đó.
III. Dagger 2 Testing với EntryPoint
Cùng với @EntryPoint
là TestEntryPointRule
sẽ cung cấp component cho mỗi test. Ngoài ra có thể tùy chỉnh test cases với @TestModule để custom dependencies
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token annotation builtin">@RunWtih</span><span class="token punctuation">(</span>AndroidJUnit4<span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span> <span class="token keyword">class</span> PlaybackTest <span class="token punctuation">{</span> <span class="token annotation builtin">@Rule</span> <span class="token keyword">val</span> testEntryPointRule <span class="token operator">=</span> <span class="token function">TestEntryPointRule</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token annotation builtin">@TestModule</span> <span class="token keyword">object</span> <span class="token keyword">class</span> PlaybackTestModule <span class="token punctuation">{</span> <span class="token annotation builtin">@Provides</span> <span class="token keyword">fun</span> <span class="token function">provideFakeDB</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token function">FakeMusicDatabase</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token annotation builtin">@Inject</span> <span class="token keyword">lateinit</span> <span class="token keyword">var</span> player<span class="token operator">:</span> Player <span class="token keyword">val</span> activity<span class="token operator">:</span> PlaybackActivity <span class="token punctuation">}</span> |
IV Tương thích tốt với Jetpack Library
Dagger 2
sẽ được xuất hiện trong Jetpack Library như ViewModel, WorkManager,..
Ở trên, Google đã recommends là sử dụng Dagger 2
cho những project trung bình và lớn..
Cuối cùng, hi vọng là Google sẽ sớm thực hiện plan này.