Dagger2实际应用篇
前言
当前基于2.38.1
源码整理出来的一篇实际应用;
现在回头看这篇文章,其实发现内容其实真的不错(对几年前自己啃源码的认可),但是之前的文章的结构性确实有点“呵呵”,反正我回头看了才发现其中主要问题:①文章没有整体思路;②不够通俗易懂;
所以有了现在对dagger2
实际应用的翻新之作,意在能让人更好的理解dagger2
。
分三部分讲解:dagger2
、dagger2-android
、 hilt
下面从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还是比较排斥的,用的不多。
那么为什么要使用依赖注入?
使用依赖注入原因:
- 依赖注入是google推出来的,和aac一起推出来的;
- 依赖注入思想其实在
spring
架构中已经被使用很久了(如果你们了解spring
源码的话); - (重点)依赖注入更注重于架构方面的调整:是为了提高开发效率、易解耦。
对一个简单的项目,或者项目成员整体水平不高的情况下,依赖注入不但不会带来实质性帮助,反而起到束缚作用。但是对于一个大型项目来说,依赖注入的思想起到非常至关重要的作用,典型的就是插拔。
什么叫插拔?
嗯,用了一个框架(比如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
类中实例化UserDao
和RepoDao
,需要传递GithubDb
参数:当前类中的provideDb
方法提供了GithubDb
参数,那么问题来了,我们如何确保GithubDb
的实例化在UserDao
和RepoDao
实例化的前面?
其实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
中,那么如何在具体的Activity
或Fragment
中使用容器中的实例化对象,如下:
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)}}
}
需要强调一点,以上所做的目的是在Activity
和Fragmen
中能够使用到注入自定义Application
中的Component
容器中的实例化对象。
完成以上步骤,我们就可以在Fragment中使用容器中的实例化对象了,用法如下:
class RepoFragment : Fragment() {@Injectlateinit var viewModelFactory: ViewModelProvider.Factory@Injectlateinit var appExecutors: AppExecutors...
}
四 hilt
五 总结
可在QQ群:575306647 讨论
以上根据源码分析得出的结论,有不足之处请指教!
源码解析github地址
Dagger2实际应用篇相关推荐
- Dagger2之应用篇(Dagger2+RxJava+Retrofit+OkHttp+MVP)-第7章
介绍 前面介绍了Dagger2,今天尝试自己的想法去应用了下,说实话很别扭,晚上睡觉思前想后这个的好处.总是有一种似懂非懂,感觉就是,让对象与对象之间产生了一中关联,多个module的provides ...
- Dagger2从入门到放弃再到恍然大悟
现在Dagger2在项目里用的越来越多了,最近花了些时间学习了一下Dagger2,这篇文章主要帮助理解Dagger2的注入实现过程,如有错误,还请指正! 什么是Dagger2 Dagger2是Dagg ...
- Android-框架-Dagger2-Dagger2从入门到放弃再到恍然大悟
原文出处:http://www.jianshu.com/p/39d1df6c877d 现在Dagger2在项目里用的越来越多了,最近花了些时间学习了一下Dagger2,这篇文章主要帮助理解Dagger ...
- Android:dagger2让你爱不释手-基础依赖注入框架篇
前言 dagger2的大名我想大家都已经很熟了,它是解决Android或java中依赖注入的一个类库(DI类库).当我看到一些开源的项目在使用dagger2时,我也有种匆匆欲动的感觉,因此就立马想一探 ...
- Android 使用dagger2进行依赖注入(基础篇)
0. 前言 Dagger2是首个使用生成代码实现完整依赖注入的框架,极大减少了使用者的编码负担, 本文主要介绍如何使用dagger2进行依赖注入.如果你不还不了解依赖注入,请看这一篇. 1. 简单的依 ...
- java dagger2_从零开始搭建一个项目(rxJava+Retrofit+Dagger2) --完结篇
鸡汤:感到迷茫是因为你没有给自己做好人生规划 接上一章的内容,如果还没看过的朋友, 请点 本章内容 Dagger2的引入 Dagger2的引入 Dagger2是一个依赖注入框架,那么dagger2能起 ...
- Dagger2 在 Android 项目的正确使用方式【完整篇】
Dagger2的入门难度极大,我们直奔主题,先使用起来 再去思考原理.网上几乎都是Java的用法,谨慎参考. 当你看到没有使用dagger.android这个库的讲解,都是Java用的,Android ...
- dagger2记录篇
作为一个码农,什么都不用多讲,贴代码 build project build module Application public class App extends Application {priv ...
- Android -- 带你从源码角度领悟Dagger2入门到放弃(三)
1, 前面两篇文章我们知道了怎么使用常用的四种标签,现在我们结合我们自己的项目中去简单的使用 在我们搭建项目的时候,一般会创建自己的Application,在里面进行一些初始化如一些第三方的Green ...
最新文章
- redis 可视化客户端
- 基于MDA的移动应用开发建模及实现
- 密码技术--非对称加密算法及Go语言应用
- 段错误 (核心已转储)_向大厂看齐!为自己的程序增加自动转储的功能!
- 安卓收藏功能怎么实现_从电源芯片的内部设计,看各个功能是怎么实现的
- ie兼容响应式布局的实现总结
- 管理活动目录域服务实训_管理学院学生党支部开展实践教育基地服务活动
- 全球最伟大50名商业领袖,任正非和马云未入选,中国只有一人上榜
- Ubuntu下安装配置java及环境变量
- Python---列表与元组
- c语言次幂如何表达_如何确保分布式场景下的并发幂等性?
- CF633C:Spy Syndrome 2——题解
- Adobe Premiere基础-编辑素材文件常规操作(脱机文件,替换素材,素材标签和编组,素材启用,便捷调节不透明度,项目打包)(十七)
- Linux系列课程之一Linux的介绍
- 数据分析(Python)贡献度分析——帕累托法则
- 20-统一网关Gateway-全局过滤器
- 极路由添加静态路由表_如何将静态TCP / IP路由添加到Windows路由表
- AI 医学影像公司及其产品(更新中)
- 妹子尚且如此! 少年努力吧
- python课程设计 文字游戏 魔塔3
热门文章
- 年产1万吨L-赖氨酸干粉工厂的设计-发酵工段及车间的设计(lunwen+CAD图纸)
- 一个30岁程序员的对于中年危机的思考和应对
- Unity-VolumeLighting组件(体积雾/光效果)使用小记
- C1073 涉及增量编译的内部错误(编译器文件“d:\agent\_work\4\s\src\vctools\Compiler\CxxFE\sl
- EMC规划BRS产品线 推动私有云建设
- 二路归并排序原理及JAVA实现
- ERNIE: 2.0带来了什么
- Python3,10行代码,制作艺术签名,从此走上人生巅峰。
- 【新书推荐】崛起的超级智能:互联网大脑如何影响科技未来
- 什么是BFC?以及形成BFC的条件