日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android 依赖注入可以更简单 —— 新版本 Dagger 2 使用教学

發(fā)布時間:2025/4/5 Android 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android 依赖注入可以更简单 —— 新版本 Dagger 2 使用教学 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

今年 3 月 21 號 Dagger 2 在 2.10 版本之后針對 Android 方面做了很大的優(yōu)化,使用方法也隨之有了不少變化。本次改動除了讓 Dagger 2 的使用更加符合控制反轉原則,還針對 Android 端做出了專門的優(yōu)化(即所謂 dagger.android) —— 大大簡化了 Android 端 Dagger 2 的使用。現(xiàn)在,不妨隨著本文一起探尋新版本 Dagger 2 的基本使用方法。


閱讀前提

要注意閱讀本文內(nèi)容前最好對 2.10 版本前的 Dagger 2 比較熟悉,至少要明白它的依賴注入管理機制,最好是實際項目中使用過,不然閱讀時會比較迷茫。當然,一切的 Dagger 2 的說明文章很多,善用搜索引擎就可以找到不錯的教程,這里就不再贅述了。
另外,本文的 demo 項目中用到了 Google Samples 項目 Android Architecture 使用的 MVP 實現(xiàn)方式,這個也最好有所了解。主要是了解它的 todo-mvp-dagger 分支的結構組織方法即可,至少要明白它的功能層次和組織結構。


以前的做法有問題?

想想我們在 2.10 版本之前是怎么在 Android 端使用 Dagger 2 的?是不是類似下面的代碼:

public class FrombulationActivity extends Activity {@Inject Frombulator frombulator;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// DO THIS FIRST. Otherwise frombulator might be null!((SomeApplicationBaseType) getContext().getApplicationContext()).getApplicationComponent().newActivityComponentBuilder().activity(this).build().inject(this);// ... now you can write the exciting code} }復制代碼

代碼例子取自 Google 官方的 Dagger 2 文檔。

emmmmm,好像也沒什么問題啊?

不,其實這段代碼大有問題!

第一點,代碼重復度過高:我們要在幾乎每一個需要注入依賴項的 Activity 和 Fragment 里面來一套這樣的代碼。這是因為我們在 Android 編程中要用到的 Activity、Fragment 等類是繼承自系統(tǒng)的,同時生命周期都由系統(tǒng)管理,所以使用 Dagger 2 的時候就不得不進行手動的處理,也就只有在純粹自己寫的 Java 類中使用 Dagger 2 才感覺更舒服一些。

第二點,違反了控制反轉原則:原有的用法使得被注入的目標類必須要了解注入管理工具的詳細信息,才能讓注入工作順利進行。即使可以通過接口使得實際代碼中不必書寫太多的實際類名,但這仍然造成了嚴重的目標類和管理類的緊耦合。

其實,我們以前在使用 Dagger 2 的時候為了解決重復問題也是使用 Live Template 或者設計一個通用的工具函數(shù);而為了保證注入目標類正常工作和注入管理正常進行,就必須在設計業(yè)務代碼的時候并行設計注入管理代碼。
幸好,2.10 版本針對 Android 系統(tǒng)做出了很大的優(yōu)化,甚至單獨做了 Android 方面的依賴注入管理庫,提供了針對 Android 的注解和輔助類大大減少了要寫的代碼。

下面我就用一個簡單的 demo 講解一下新版本的 Dagger 2 的基本使用方法,項目地址 請戳這里。注意項目有兩個分支,master 分支用來演示基本使用方法,simplify 分支演示簡化用法。


基本使用方法

實際上,新版本的 Dagger 2 可以有多種使用方式,需要用戶構建不同數(shù)量的接口、抽象類,但我們先不將最簡化的使用方式,因為用基本但復雜的方法更好理解 Dagger 2 的使用邏輯和結構。
要使用基本的功能,只需要在 app 的 build.gradle 文件中加入下列依賴代碼:

implementation 'com.google.dagger:dagger:2.13' implementation 'com.google.dagger:dagger-android-support:2.13' annotationProcessor 'com.google.dagger:dagger-compiler:2.13'復制代碼

Application 注入管理

Application 的注入基本沒有什么變化,更多的是 Dagger 2 官方建議最好使用 Builder 模式構建 Component,方便靈活的向 Component 中添加構建屬性,比如:

@Singleton @Component(modules = AppModule.class) public interface AppComponent {void inject(MyApplication application);@Component.Builderinterface Builder {@BindsInstanceBuilder application(Application application);AppComponent build();} }復制代碼

Module 和舊版相比沒什么太大變化:

@Module public class AppModule {@Singleton@ProvidesContext provideContext(Application application) {return application;} }復制代碼

而一般在調(diào)用數(shù)據(jù)庫或存取 SharedPreferences 文件時,常常用到 Context,一般會提供 Application 而非 Activity 等。

Activity 注入管理

第一,是方便管理多級 Component,要求在最頂層的即 Application 的 Component 中引入 AndroidInjectionModule 或 AndroidSupportInjectionModule,代碼形式如下:

@Singleton @Component(modules = {AppModule.class, AndroidSupportInjectionModule.class}) public interface AppComponent {// ... }復制代碼

@BindInstance 注解方便在 Builder 中加入設置項,傳入要求的實例就能設置 Builder 中的對應屬性。

第二,Activity 的 Component(也可以是某個功能模塊的 Component)用 @Subcomponent 注解而非 @Component,同時它還要繼承 AndroidInjector<T>(T 一般為對應的 Activity)。當然,如果有對應的 Module 也不要忘記在注解中用 moduls 添加。比如:

@ActivityScoped @Subcomponent(modules = MainActivityModule.class) public interface MainActivityComponent extends AndroidInjector<MainActivity> {@Subcomponent.Builderabstract class Builder extends AndroidInjector.Builder<MainActivity> {} }復制代碼

此處 的 Builder 可繼承 AndroidInjector.Builder<T>,必須對應 @Subcomponent.Builder 注解的抽象類,方便生成 Builder 代碼。

第三,要在第二步中的 Subcomponent 的父 Module 中用注解標記出 Subcomponents 的內(nèi)容。
可以把 AppModule 當作父 Module:

@Module(subcomponents = {MainActivityComponent.class}) public class AppModule {@Singleton@ProvidesContext provideContext(Application application) {return application;} }復制代碼

也可以另外寫一個 `ActivityBindingModule 當作父 Module:

@Module(subcomponents = {MainActivityComponent.class, DummyActivityComponent.class}) public abstract class ActivityBindingModule {// ... }復制代碼

相對來說,subcomponents 寫在哪里其實并不重要,ActivityBindingModule 也不止這個上面一個作用,但個人認為寫到這里更方便管理。

第四,綁定 Subcomponent 的 Builder 到 AndroidInjector.Factory<T>,方便 Dagger 2 借助正確的 Builder 類型生成對應的 AndroidInjector 代碼,為方便管理最好寫到一個統(tǒng)一的 Module 中:

@Module(subcomponents = {MainActivityComponent.class, DummyActivityComponent.class}) public abstract class ActivityBindingModule {@Binds@IntoMap@ActivityKey(MainActivity.class)abstract AndroidInjector.Factory<? extends Activity> bindMainActivityInjectorFactory(MainActivityComponent.Builder builder); }復制代碼

第五,把第四不得 Module 信息加入到 Application 的 Component 注解:

@Singleton @Component(modules = {AppModule.class, ActivityBindingModule.class,AndroidSupportInjectionModule.class} ) public interface AppComponent {// ... }復制代碼

注意:我這里沒有采用官方文檔的寫法,使用 Activity 的 Module 來管理 subcomponents 屬性,以及綁定 Builder。因為本文描述的方案邏輯上更好理解,也能更集中地管理相似的代碼,這也是從 Google Samples 演示項目 Android Architecture 學到的方法。

Fragment 注入管理

如果需要對 Fragment 設置單獨的注入管理類,那么可以參考 Activity 的方式,不同的是父類的 Module 信息要放到 Activity 的 Component 注解中,所有管理類信息如下(本例中也用到了簡單的 MVP 結構):

DummyActivity 相關:

@ActivityScoped @Subcomponent(modules = {DummyActivityModule.class, DummyFragmentBindingModule.class}) public interface DummyActivityComponent extends AndroidInjector<DummyActivity> {@Subcomponent.Builderabstract class Builder extends AndroidInjector.Builder<DummyActivity> {} } /*************************************/ @Module public class DummyActivityModule {@ActivityScoped@ProvidesDummyContract.Presenter provideDummyPresenter(DummyPresenter presenter) {return presenter;} }復制代碼

DummyFragment 相關:

@Module(subcomponents = DummyFragmentComponent.class) public abstract class DummyFragmentBindingModule {@Binds@IntoMap@FragmentKey(DummyFragment.class)abstract AndroidInjector.Factory<? extends Fragment> bindDummyFragment(DummyFragmentComponent.Builder builder); } /*************************************/ @FragmentScoped @Subcomponent(modules = DummyFragmentModule.class) public interface DummyFragmentComponent extends AndroidInjector<DummyFragment> {@Subcomponent.Builderabstract class Builder extends AndroidInjector.Builder<DummyFragment> {} } /*************************************/ @Module public class DummyFragmentModule {@FragmentScoped@ProvidesDummyContract.View provideDummyView(DummyFragment fragment) {return fragment;}// ... }復制代碼

本例子中的 MVP 實現(xiàn)方式,參考了 Google Samples 的 Android Architecture 的 todo-mvp-dagger 分支,即把 Activity 僅僅當作 Fragment 的管理容器,Fragment 作為 MVP 中的 View 角色來對待。

完成注入

第一,Applicaiton 要實現(xiàn)接口 HasActivityInjector,用來實現(xiàn)自動管理 Activity 的 Injector,具體實現(xiàn)方法是固定不變的:

public class MyApplication extends Application implements HasActivityInjector {@InjectDispatchingAndroidInjector<Activity> mInjector;@Overridepublic void onCreate() {super.onCreate();DaggerAppComponent.builder().application(this).build().inject(this);}@Overridepublic AndroidInjector<Activity> activityInjector() {return mInjector;} }復制代碼

第二,無需管理 Fragment 的 Injector 的 Activity 直接注入自己需要的依賴即可:

public class MainActivity extends BaseActivity {// ...@Overrideprotected void onCreate(Bundle savedInstanceState) {AndroidInjection.inject(this);super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);} }復制代碼

第三,需要管理 Fragment 的 Injector 的 Activity 需要實現(xiàn)接口 HasSupportFragmentInjector,方式類似第一步:

public class DummyActivity extends BaseActivityimplements HasSupportFragmentInjector {@Inject DispatchingAndroidInjector<Fragment> mInjector;// ...@Overrideprotected void onCreate(final Bundle savedInstanceState) {AndroidInjection.inject(this);super.onCreate(savedInstanceState);setContentView(R.layout.activity_dummy_layout);// ...}// ...@Overridepublic AndroidInjector<Fragment> supportFragmentInjector() {return mInjector;} }復制代碼

第四,對 Fragment 注入依賴:

public final class DummyFragment extends BaseFragment {// ...@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {AndroidSupportInjection.inject(this);View view = inflater.inflate(R.layout.fragment_dummy_layout, container, false);unbinder = ButterKnife.bind(this, view);return view;}// ... }復制代碼

簡化用法

仔細觀察上面的例子,我們應該能發(fā)現(xiàn)其實新版本的 Dagger 2 并沒有更改原來的設定:仍然使用 Component 作注入器,使用 Module 作依賴提供者,也仍然使用多層級樹形 Component 來統(tǒng)合管理整個項目的依賴,同時 @Quilifier 和 @Scope 的作用也沒變。僅僅只是把每個 Activity 和 Fragment 的注入代碼精簡了,無需知道注入的詳細細節(jié)了。
但是,僅僅如此的化,你一定會很疑惑:這個改法確實是更符合依賴反轉原則了,可實在也沒節(jié)省多少代碼啊?別急,基本用法一般只是用來了解原理的,實際使用不會這么干的!

簡化管理類

首先,我們要考慮到底是什么代碼重復最多,最容易使用工具生成呢?當然是 @Subcomponent 標注的代碼!因為上面的例子中我們可以看出它們的功能相對較為簡單,只是為了構建一個樹形結構方便管理,所以大部分編程情景下這部分的代碼其實沒有什么額外的功能。而 Dagger 2 也貼心的提供了簡化的方案:
只要 @Subcomponent標注的 Component 類滿足以下條件,就能簡化:

  • 除了對應的 Builder 外沒有其他的方法
  • Builder 類也不會添加其他的方法去自定義構建屬性

在簡化之前,要先在 app 的 build.gradle 文件中添加下述依賴:

annotationProcessor 'com.google.dagger:dagger-android-processor:2.13'復制代碼

然后,就能使用 APT 工具自動生成相應的 @Subcomponent 代碼,比如 Activity 的 Component 就無需再寫,而是在 ActivityBindingModule 中寫入如下的代碼:

@Module public abstract class ActivityBindingModule {@ActivityScoped@ContributesAndroidInjector(modules = MainActivityModule.class)abstract MainActivity bindMainActivity();@ActivityScoped@ContributesAndroidInjector(modules = {DummyActivityModule.class, DummyFragmentBindingModule.class})abstract DummyActivity bindDummyActivity(); }復制代碼

而 Fragment 的 @Subcomponent 注解也如法炮制:

@Module public abstract class DummyFragmentBindingModule {@FragmentScoped@ContributesAndroidInjector(modules = DummyFragmentModule.class)abstract DummyFragment bindDummyFragment(); }復制代碼

注意: DummyFragmentBindingModule 的注解信息必須加到同 DummyActivityModule 一樣的地方,即本例中的 bindDummyActivity() 的注解中。

這樣,即使 Activity 大量增加也不用寫大量沒什么變化的 Component 代碼了。當然 Module 還是需要的,只不過也可以有部分的簡化。

比如 Applicaiton 的 Module 使用 @Binds 把 Application 實例和 Context 進行綁定:

@Module public abstract class AppModule {@Bindsabstract Context provideContext(Application application); }復制代碼

同理,在 MVP 中如果需要提供 Presenter 接口也可以使用這個辦法,比如:

@Module public abstract class DummyActivityModule {@ActivityScoped@Bindsabstract DummyContract.Presenter bindDummyPresenter(DummyPresenter presenter); }復制代碼

只不過這個辦法只能把傳入的實例和返回類型進行綁定,其他復雜的依賴提供方法(比如需要利用傳入?yún)?shù)手動實例化,或進行條件判斷)還是不能簡化的。(這不是廢話嗎...)

簡化注入操作

注入操作很明顯可以簡化,畢竟模式完全相同,簡化的方法就是提供了模板父類 DaggerApplication、DaggerAppCompatActivity 和 DaggerFragment,然后讓需要注入操作的類繼承它們即可。
最后,Application 的代碼就如下所示:

public class MyApplication extends DaggerApplication {@Overrideprotected AndroidInjector<? extends DaggerApplication> applicationInjector() {return DaggerAppComponent.builder().application(this).build();} }復制代碼

而 Activity 和 Fragment 則最好是讓 BaseActivity 和 BaseFragment 去繼承上面提到的兩個模板父類,在一般的代碼中自只需要用 @Inject 標出需要注入的元素即可,無需任何額外操作。這樣,在編寫 Activity 和 Fragment 的時候無需考慮依賴注入的細節(jié),只要按照正常流程編寫代碼,然后不斷檢查、測試代碼,不斷標記出需要注入的元素即可。

最后,再次提醒相關代碼不可能全部演示出來,可以去 Dagger 2 Android Demo 查看具體細節(jié),尤其簡化部分的代碼重復內(nèi)容較多文章不作贅述,需要的可以自行查看 simplify 分支。另外,如果項目有 bug 也歡迎直接提出 issue。


參考

  • Dagger 2 官方 Android 使用文檔
  • New Android Injector with Dagger 2?—?part 1
  • New Android Injector with Dagger 2?—?part 2

轉載于:https://juejin.im/post/5a20b606f265da430e4ef364

總結

以上是生活随笔為你收集整理的Android 依赖注入可以更简单 —— 新版本 Dagger 2 使用教学的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 精品久草 | 伊人久久91| 欧美激情区 | 国产乱码精品一区二区三区忘忧草 | 日日爱av | 99re5| a毛片在线免费观看 | av网址免费在线观看 | 99精品国自产在线 | 国产一区二区三区视频 | 日本久久久久久久久 | 精品午夜一区二区三区在线观看 | av中文在线天堂 | 青青青手机视频在线观看 | 欧美一级淫片 | 综合久久一区 | 亚洲综合日韩 | 国产啊v在线 | 无遮挡的裸体按摩的视频 | 毛片毛片毛片毛片毛片毛片毛片毛片毛片 | 久久久久久伦理 | 8x8ⅹ国产精品一区二区 | 插插插网站| 国产精品一区免费 | 亚洲国产一区二区在线 | 光溜溜视频素材大全美女 | 亚洲av无码成人精品区 | 国产一区久久 | 日韩成人av影院 | 神马午夜伦理 | 色爱综合网 | 久久久精品人妻一区二区三区色秀 | 91禁外国网站 | 精品一区二区中文字幕 | 日本一区欧美 | 操综合| 红桃视频网站 | 欧美激情视频二区 | 免费看裸体视频网站 | 日本aⅴ视频 | 伊人网色 | 手机看片福利一区 | 日韩一级免费看 | 国产鲁鲁视频在线观看特色 | 日本成人一区二区 | 伊人久久久久久久久久久 | 国产成人精品无码高潮 | 99爱免费视频 | 亚洲熟伦熟女新五十路熟妇 | 欧美人成在线 | 国产乱仑视频 | 99久久99久久精品国产片果冰 | 亚洲蜜桃av一区二区 | 国产一区二区片 | 96av在线| 制服丝袜一区在线 | 国产丝袜网站 | www夜插内射视频网站 | 久久视频一区二区三区 | 欧美色婷婷 | av超碰 | 国产黄色在线网站 | 精品伦一区二区三区 | 新香蕉视频 | 猛1被调教成公厕尿便失禁网站 | 少妇全黄性生交片 | 国产亚洲欧美一区二区三区 | 日本a大片 | 肉肉av福利一精品导航 | 99re伊人| 毛片在线播放视频 | 日本xxx在线播放 | 中文字幕一区二区三区夫目前犯 | 成人在线观看亚洲 | 狂野欧美性猛交xxxx | 欧美卡一卡二卡三 | 91超薄肉色丝袜交足高跟凉鞋 | 黄色永久视频 | 视频一区日韩 | 久久99精品国产麻豆婷婷 | 欧美国产一区二区在线观看 | 亚洲天堂手机 | 日日网站| 国产精品免费一区二区三区 | 亚洲第一视频网 | 大奶在线播放 | 中文字幕 亚洲一区 | 玖玖玖国产精品 | 日韩激情四射 | 日本www高清视频 | 欧美老熟妇乱xxxxx | 好吊色视频988gao在线观看 | 午夜精 | 久草视频免费 | 久久精品影视 | 亚洲天堂成人在线观看 | 成人午夜视频精品一区 | 日本成人一区二区三区 | 色综合中文综合网 |