前言

当前基于2.38.1源码整理出来的一篇实际应用;

现在回头看这篇文章,其实发现内容其实真的不错(对几年前自己啃源码的认可),但是之前的文章的结构性确实有点“呵呵”,反正我回头看了才发现其中主要问题:①文章没有整体思路;②不够通俗易懂;

所以有了现在对dagger2实际应用的翻新之作,意在能让人更好的理解dagger2

分三部分讲解:dagger2dagger2-androidhilt

下面从dagger2主体到细节,并且运用实际案例逐一讲解各个注解的实际应用。

以下叙述的案例主体来源于aac的GithubBrawserSample,可自行下载查看。

一 依赖注入-DI

DI-Dependency Injection。在java中我们正常使用一个对象:

A  a = new A();

通过依赖注入:

(1)首先创建一个容器C对象,这个容器C对象生命周期和项目绑定-C容器随着项目的创建而创建,随着项目的销毁而销毁;容器中创建一个A对象:

public class C{A a;public static C c;public static newInstance(){if(c = null){ c = new C();}return c;}public void instance(){a = new A();}public A getA(){return a;}
}

我们可以在MyApplication的oncreate方法中通过C.newInstance()实例化C对象。

(2)当我们要使用A对象时,直接在C对象中获取到实例化的A即可,如下B对象要使用A对象了

public class B{private A a = MyApplication.getC().getA();...
}

这个就是一套依赖注入的思想。是不是感觉有点神经病,我特么好好得new对象不香吗,这么麻烦。

确实。很多时候没必要这么去做,并不是每个项目都需要通过依赖注入去做的,而且实现也比较麻烦,也不容易懂。项目开发成本随之提高,尤其现在国内对Dagger2还是比较排斥的,用的不多。

那么为什么要使用依赖注入?

使用依赖注入原因:

  1. 依赖注入是google推出来的,和aac一起推出来的;
  2. 依赖注入思想其实在spring架构中已经被使用很久了(如果你们了解spring源码的话);
  3. (重点)依赖注入更注重于架构方面的调整:是为了提高开发效率、易解耦。

对一个简单的项目,或者项目成员整体水平不高的情况下,依赖注入不但不会带来实质性帮助,反而起到束缚作用。但是对于一个大型项目来说,依赖注入的思想起到非常至关重要的作用,典型的就是插拔

什么叫插拔?

嗯,用了一个框架(比如glide),感觉不符合当前项目需求了(想换一个图片加载机制),我要换一个,这个时候就体现依赖注入的重要性了。

android实现依赖注入最好的办法就是Dagger2架构。

二 dagger2

主体案例

AppComponent.kt

@Singleton
@Component(modules = [//modules节点的作用就是往容器中实例化对象...,AppModule::class]
)
interface AppComponent {@Component.Builderinterface Builder {//传递参数@BindsInstancefun application(application: Application): Builder//实例化AppComponent对象fun build(): AppComponent}//将当前Appcomponent容器注入GithubApp中fun inject(githubApp: GithubApp)
}

调用DaggerAppComponent.builder().application(githubApp).build().inject(githubApp)表示容器注入到GithubApp中。

AppModule.kt

@Module(includes = [ViewModelModule::class])//includes表示子module节点,同样表示往容器中实例化对象
class AppModule {@Singleton@Providesfun provideGithubService(): GithubService {//实例化GithubService 对象return Retrofit.Builder().baseUrl("https://api.github.com/").addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(LiveDataCallAdapterFactory()).build().create(GithubService::class.java)}@Singleton@Providesfun provideDb(app: Application): GithubDb {//实例化GithubDb 对象,当前方法参数来源于AppComponent 类的Builder类application方法return Room.databaseBuilder(app, GithubDb::class.java, "github.db").fallbackToDestructiveMigration().build()}@Singleton@Providesfun provideUserDao(db: GithubDb): UserDao {//实例化UserDao 对象return db.userDao()}@Singleton@Providesfun provideRepoDao(db: GithubDb): RepoDao {//实例化RepoDao 对象return db.repoDao()}
}

AppModule类中实例化UserDaoRepoDao,需要传递GithubDb参数:当前类中的provideDb方法提供了GithubDb参数,那么问题来了,我们如何确保GithubDb的实例化在UserDaoRepoDao 实例化的前面?

其实Dagger源码在容器中实例化对象之前,会做一个排列。某某对象实例化需要引用到另外对象,做一个顺序排列,Dagger会很好的掌握对象实例化顺序。

AppModule.kt还包含一个子module节点

ViewModelModule.kt

@Suppress("unused")
@Module
abstract class ViewModelModule {@Binds@IntoMap@ViewModelKey(UserViewModel::class)abstract fun bindUserViewModel(userViewModel: UserViewModel): ViewModel@Binds@IntoMap@ViewModelKey(SearchViewModel::class)abstract fun bindSearchViewModel(searchViewModel: SearchViewModel): ViewModel@Binds@IntoMap@ViewModelKey(RepoViewModel::class)abstract fun bindRepoViewModel(repoViewModel: RepoViewModel): ViewModel@Bindsabstract fun bindViewModelFactory(factory: GithubViewModelFactory): ViewModelProvider.Factory
}

这个类主要是通过GithubViewModelFactory实例化UserViewModel、SearchViewModel和RepoViewModel对象;

bindUserViewModel方法参数通过class UserViewModel @Inject constructor(userRepository: UserRepository, repoRepository: RepoRepository) :Inject注解修饰构造函数实例化;

也就是说到目前为止,实例化对象可以通过module节点的方法,还可以通过Inject修饰构造函数的方式。

2.重要注解

3.衍生注解

4.其他注解

三 dagger2-android

DaggerAppComponent.builder().application(githubApp).build().inject(githubApp)和以上主体案例仅仅是将当前实例化后的容器注入到自定义Application中,那么如何在具体的ActivityFragment中使用容器中的实例化对象,如下:

AppComponent

@Singleton
@Component(modules = [AndroidInjectionModule::class,...,MainActivityModule::class]
)
interface AppComponent {...}

MainActivityModule

@Suppress("unused")
@Module
abstract class MainActivityModule {@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])abstract fun contributeMainActivity(): MainActivity
}

FragmentBuildersModule

@Suppress("unused")
@Module
abstract class FragmentBuildersModule {@ContributesAndroidInjectorabstract fun contributeRepoFragment(): RepoFragment@ContributesAndroidInjectorabstract fun contributeUserFragment(): UserFragment@ContributesAndroidInjectorabstract fun contributeSearchFragment(): SearchFragment
}

GithubApp

class GithubApp : Application(), HasActivityInjector {@Injectlateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>...override fun activityInjector() = dispatchingAndroidInjector
}

MainActivity

class MainActivity : AppCompatActivity(), HasSupportFragmentInjector {@Injectlateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>...override fun supportFragmentInjector() = dispatchingAndroidInjector
}

AppInjector

object AppInjector {fun init(githubApp: GithubApp) {DaggerAppComponent.builder().application(githubApp).build().inject(githubApp)githubApp.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {handleActivity(activity)}override fun onActivityStarted(activity: Activity) {}override fun onActivityResumed(activity: Activity) {}override fun onActivityPaused(activity: Activity) {}override fun onActivityStopped(activity: Activity) {}override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}override fun onActivityDestroyed(activity: Activity) {}})}private fun handleActivity(activity: Activity) {if (activity is HasSupportFragmentInjector) {AndroidInjection.inject(activity)}if (activity is FragmentActivity) {activity.supportFragmentManager.registerFragmentLifecycleCallbacks(object : FragmentManager.FragmentLifecycleCallbacks() {override fun onFragmentCreated(fm: FragmentManager,f: Fragment,savedInstanceState: Bundle?) {if (f is Injectable) {AndroidSupportInjection.inject(f)}}}, true)}}
}

需要强调一点,以上所做的目的是ActivityFragmen中能够使用到注入自定义Application中的Component容器中的实例化对象。

完成以上步骤,我们就可以在Fragment中使用容器中的实例化对象了,用法如下:

class RepoFragment : Fragment() {@Injectlateinit var viewModelFactory: ViewModelProvider.Factory@Injectlateinit var appExecutors: AppExecutors...
}

四 hilt

五 总结

可在QQ群:575306647 讨论

以上根据源码分析得出的结论,有不足之处请指教!

源码解析github地址

Dagger2实际应用篇相关推荐

  1. Dagger2之应用篇(Dagger2+RxJava+Retrofit+OkHttp+MVP)-第7章

    介绍 前面介绍了Dagger2,今天尝试自己的想法去应用了下,说实话很别扭,晚上睡觉思前想后这个的好处.总是有一种似懂非懂,感觉就是,让对象与对象之间产生了一中关联,多个module的provides ...

  2. Dagger2从入门到放弃再到恍然大悟

    现在Dagger2在项目里用的越来越多了,最近花了些时间学习了一下Dagger2,这篇文章主要帮助理解Dagger2的注入实现过程,如有错误,还请指正! 什么是Dagger2 Dagger2是Dagg ...

  3. Android-框架-Dagger2-Dagger2从入门到放弃再到恍然大悟

    原文出处:http://www.jianshu.com/p/39d1df6c877d 现在Dagger2在项目里用的越来越多了,最近花了些时间学习了一下Dagger2,这篇文章主要帮助理解Dagger ...

  4. Android:dagger2让你爱不释手-基础依赖注入框架篇

    前言 dagger2的大名我想大家都已经很熟了,它是解决Android或java中依赖注入的一个类库(DI类库).当我看到一些开源的项目在使用dagger2时,我也有种匆匆欲动的感觉,因此就立马想一探 ...

  5. Android 使用dagger2进行依赖注入(基础篇)

    0. 前言 Dagger2是首个使用生成代码实现完整依赖注入的框架,极大减少了使用者的编码负担, 本文主要介绍如何使用dagger2进行依赖注入.如果你不还不了解依赖注入,请看这一篇. 1. 简单的依 ...

  6. java dagger2_从零开始搭建一个项目(rxJava+Retrofit+Dagger2) --完结篇

    鸡汤:感到迷茫是因为你没有给自己做好人生规划 接上一章的内容,如果还没看过的朋友, 请点 本章内容 Dagger2的引入 Dagger2的引入 Dagger2是一个依赖注入框架,那么dagger2能起 ...

  7. Dagger2 在 Android 项目的正确使用方式【完整篇】

    Dagger2的入门难度极大,我们直奔主题,先使用起来 再去思考原理.网上几乎都是Java的用法,谨慎参考. 当你看到没有使用dagger.android这个库的讲解,都是Java用的,Android ...

  8. dagger2记录篇

    作为一个码农,什么都不用多讲,贴代码 build project build module Application public class App extends Application {priv ...

  9. Android -- 带你从源码角度领悟Dagger2入门到放弃(三)

    1, 前面两篇文章我们知道了怎么使用常用的四种标签,现在我们结合我们自己的项目中去简单的使用 在我们搭建项目的时候,一般会创建自己的Application,在里面进行一些初始化如一些第三方的Green ...

最新文章

  1. redis 可视化客户端
  2. 基于MDA的移动应用开发建模及实现
  3. 密码技术--非对称加密算法及Go语言应用
  4. 段错误 (核心已转储)_向大厂看齐!为自己的程序增加自动转储的功能!
  5. 安卓收藏功能怎么实现_从电源芯片的内部设计,看各个功能是怎么实现的
  6. ie兼容响应式布局的实现总结
  7. 管理活动目录域服务实训_管理学院学生党支部开展实践教育基地服务活动
  8. 全球最伟大50名商业领袖,任正非和马云未入选,中国只有一人上榜
  9. Ubuntu下安装配置java及环境变量
  10. Python---列表与元组
  11. c语言次幂如何表达_如何确保分布式场景下的并发幂等性?
  12. CF633C:Spy Syndrome 2——题解
  13. Adobe Premiere基础-编辑素材文件常规操作(脱机文件,替换素材,素材标签和编组,素材启用,便捷调节不透明度,项目打包)(十七)
  14. Linux系列课程之一Linux的介绍
  15. 数据分析(Python)贡献度分析——帕累托法则
  16. 20-统一网关Gateway-全局过滤器
  17. 极路由添加静态路由表_如何将静态TCP / IP路由添加到Windows路由表
  18. AI 医学影像公司及其产品(更新中)
  19. 妹子尚且如此! 少年努力吧
  20. python课程设计 文字游戏 魔塔3

热门文章

  1. 年产1万吨L-赖氨酸干粉工厂的设计-发酵工段及车间的设计(lunwen+CAD图纸)
  2. 一个30岁程序员的对于中年危机的思考和应对
  3. Unity-VolumeLighting组件(体积雾/光效果)使用小记
  4. C1073 涉及增量编译的内部错误(编译器文件“d:\agent\_work\4\s\src\vctools\Compiler\CxxFE\sl
  5. EMC规划BRS产品线 推动私有云建设
  6. 二路归并排序原理及JAVA实现
  7. ERNIE: 2.0带来了什么
  8. Python3,10行代码,制作艺术签名,从此走上人生巅峰。
  9. 【新书推荐】崛起的超级智能:互联网大脑如何影响科技未来
  10. 什么是BFC?以及形成BFC的条件