Dagger2快速入门和原理解析

转载请标明出处https://www.jianshu.com/p/9075ef1bc49a

前言:最近沉迷于学习和回顾Android知识,在dagger2的回顾之中我发现和其他高阶框架有相似的思想。所以开了这篇文章,想要对dagger2的实现原理和基本写法做一个简单的概括。分析也是基于dagger2的2.28版本进行分析。

1.dagger2的前世今生

一开始swankjesse的dagger1先面世。而后由Google接收并开发出了dagger2版本。两者都旨在业务逻辑各部分之间的耦合度降低,提高程序比如说实例化对象的可重用性,释放内存中不再需要的对象,从而提升应用性能。

2.dagger1和dagger2的区别

dagger1的实现是基于反射的。而dagger2是通过APT来实现的,去进行依赖注入。

3.dagger2的基本使用

在开始之前先说明一下dagger2的3个概念,一个是依赖对象,依赖关系集合,依赖诉求。所以注解也大致分为3种:
依赖对象:Provides(标记返回对象的方法)、 Binds(标记抽象方法或接口)
依赖关系集合:module
依赖诉求:Inject
Component(依赖和诉求之间桥梁)。
还有一个作用域注解,下文会提到。

implementation 'com.google.dagger:dagger:2.28'
annotationProcessor 'com.google.dagger:dagger-compiler:2.28'

项目依赖引入。假设想要实例化一个User对象,先用Inject标记。之后编写Module类,用Module标记,里面集合了各种依赖,比如依赖对象的返回方法。最后编写Component将依赖和诉求联系起来。

public class HomeActivity extends Activity {
    @Inject
    User user;
@Module
public class UserModule {
    @Singleton
    @Provides
    public User getUser() {
        return new User("dagger2", "dagger2");
    }
}
@Singleton
@Component(modules = UserModule.class)
public interface MainComponent {
    void inject(HomeActivity activity);

}

使用可以说是非常简单,这里还用到Singleton,是javax.inject 软件包随附的唯一一个作用域注释。可以用来标记应用中重复使用的对象。这样一来可以业务上一个对象重复使用。

对于dagger2而言,作用域是很重要的概念,官方文档也是花费了大量篇幅在处理作用域上面。因为作用域直接影响了实例化对象是重复使用还是重新创建。因为有的对象创建成本高,且是经常重复使用的,这种最好是能指定作用域到整个应用。而有的对象,用户是希望他是一个始终不同的。这里就关系到对于对象的作用域设定。翻看文档,官方始终是推荐自定义作用域的。
dagger2.jpg

上面提到了Singleton软件包里提供的唯一一个作用域注释,通过我们自定义,也能达到我们想要的效果。
并且官方提到,作用域的实现不应该跟目的挂钩,而应该跟生命周期挂钩。因为该注释可以被同级组件多次使用。

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {}

4.dagger2的进阶使用

Dagger2还涉及到关于子组件作用域以及组件化下的依赖操作。
在子组件的实际环境中,Singleton已经不足以开发使用。因为不同的业务逻辑下,对于对象实例化的要求不一样,有时希望对象重复可使用,有时希望对象不断生成新的实例化。
在dagger2中,可以使用subcomponents 注释,由MainComponent负责注入,做到子组件获取父组件作用域,因而可以使用父组件的所有对象。
且Component 是在 Activity 的 onCreate() 方法中创建的,将随着 Activity 的销毁而被隐式销毁。

@Subcomponent
public interface MainComponent {

    @Subcomponent.Factory
    interface Factory {
        MainComponent create();
    }

    void inject(HomeActivity HomeActivity);
}
@Module(subcomponents = MainComponent.class)
public class SubcomponentsModule {
}
@Singleton
@Component(modules = { SubcomponentsModule.class} )
public interface ApplicationComponent {
MainComponent.Factory MainComponent();
}
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        loginComponent = ((MyApplication) getApplicationContext())
                                .appComponent.MainComponent().create();
        loginComponent.inject(this);
    }

这时候我们业务上需要指定对象的作用域,就可以通过创建自定义注释作用域来决定对象的作用域。

//这里也可以是一个ViewModel
@Module
public class UserModule {
    //@ApplicationScope,作用域则定于整个APP生命周期
    @ActivityScope
    @Provides
    public User getUser() {
        return new User("dagger2", "dagger2");
    }
}
@ActivityScope
@Component(modules = UserModule.class)
public interface MainComponent {
    void inject(HomeActivity activity);
}

组件化下,父级组件并不知道子级的存在,所以无法像子组件那样去进行SubcomponentsModule 操作。
所以应该使用到dependencies和Factory。

 @Component(dependencies = ApplicationComponent.class)
    public interface MainComponent {

        @Component.Factory
        interface Factory {
            MainComponent create(ApplicationComponent component);
        }
        void inject(HomeActivity homeActivity);
    }

5.dagger2的原理

那么,dagger2是怎么实现的呢,抱着好奇的心态我点开了APT生成的代码。
dagger2-2.jpg

dagger2-3.png

dagger2-4.png
直接贴上源码,从create方法开始看,发现生成类的create方法走了一个内部builder类的实例化,走了Component类的initialize方法,这里维护了一个Factory工厂类,持有了userModule对象。provider是一个对于Factory的判空方法。当我们去inject的时候,实际上会去这个工厂类进行get,在这个get的过程也进行了一次判空操作。最终走了Injector类的injectUser方法,实现了一个对于activity的对象赋值的操作。

6.dagger2的优劣

dagger的确是可以省去很多实例化代码并且避免代码编写带来的逻辑内存问题。十分解耦。
劣势大概就是代码对新手不友好,真的就是见仁见智了。可以看项目情况使用。

7.题外话

其实对于dagger2的源码阅读难度并不大,dagger这个框架运用上APT预编译,APT在高阶框架上不时就能看到。
IOC :DataBinding,Dagger,Dagger2,Eventbus等。
反射:Eventbus2,Dagger等
APT:Eventbus3,Dagger2,DataBinding等
总结起来会发现,反射在资源消耗性能方面最近是越来越不受人待见,连官方都更倾向于APT直接生成模板代码。java web上的概念也被不断的运用到Android上,Android真的越来越壮大了。(APT感觉是大神必经之路,想要熟练使用,任重而道远。)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341