安卓开发 第一篇 关于依赖注入框架dagger2的使用和理解

(这篇博客真是磨难重重啊,写到一半电脑蓝屏了,还好markdown编辑器保持了部分类容)

最近开始重构项目,在重构项目中用到了依赖注入框架dagger2,发现它确实很方便,能大大加快我们编写代码的速度,同时也很方便我们对于功能模块的解耦。在这里就不过多介绍dagger2了,大家谷歌 百度一下就能得到很多关于dagger2的介绍。学习dagger2是需要一定的学习成本的,我自己开始学习的时候也差不多花了一周的时间才弄明白怎样使用dagger2,下面就说说自己对dagger2的理解和使用方法。

  1. dagger2中最重要的就是module和component了,module是生产我们需要的对象的地方,component是联系module和module生产出的对象的使用场景的桥梁。(说白了,dagger2就像是设计模式中的工厂模式,为我们生产各种我们需要的对象)

    不明白?上代码:(假如我们有一个类A,然后我们通过依赖注入方法要在MainActivity中使用)

×××××××××××××××××××××××不使用dagger2××××××××××××××××××××××××
//类A
public class A {
    private  int field;
      ...       //其他属性

    public A() {
    }

    public void doSomething(){
        Log.i("美女","我爱你");
    }

    public void doOtherthing(){
        Log.i("美女","我是真的爱你");
    }
    ...    //其他方法
}
//类MainActivity
public class MainActivity extends AppCompatActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        A a=new A();
        a.doSomething();
        a.doOtherthing();
    }
}

×××××××××××××××××××××××使用dagger2××××××××××××××××××××××××
//类A
 public class A {
    private  int field;
      ...       //其他属性

    public A() {
    }

    public void doSomething(){
        Log.i("美女","我爱你");
    }

    public void doOtherthing(){
        Log.i("美女","我是真的爱你");
    }
    ...    //其他方法
}
//我们先要构造一个Module,这个Module中生产A的对象
@Module
public class AMedule {

    @Provides
    A  provideA(){
        return  new A();
    }

}

//然后需要一个Component,用了连接Module和MainActivity
@Component(modules = AMedule.class)
public interface ActivityComponent {
   A a();
}

//在MainActivity类中使用
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ActivityComponent component=DaggerActivityComponent.builder()
                .aMedule(new AMedule())
                .build();

        A a=component.a();
        a.doSomething();
        a.doOtherthing();
    }
}

一个简单的依赖注入就完成了。也许大家会觉得这样写很麻烦,其实不然,还有一种更加简单的方法来做这件事,我们把B注入到BComponent中,直接使用@Inject注解:

//类A
 public class A {
    private  int field;
      ...       //其他属性

    public A() {
    }

    public void doSomething(){
        Log.i("美女","我爱你");
    }

    public void doOtherthing(){
        Log.i("美女","我是真的爱你");
    }
    ...    //其他方法
}
//我们先要构造一个Module
@Module
public class AMedule {

    @Provides
    A  provideA(){
        return  new A();
    }

}
//然后需要一个Component
@Component(modules = AMedule.class)
public interface ActivityComponent {
    void inject(MainActivity mainActivity);
}

//在MainActivity类中使用
public class MainActivity extends AppCompatActivity {
    @Inject
    A a;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       DaggerActivityComponent.builder()
                .aMedule(new AMedule())
                .build()
                .inject(this);

        a.doSomething();
        a.doOtherthing();
    }
}

怎么样,是不是简单,方便一些了。什么?还麻烦,那我们更进一步吧(由于这里的A类是我们自己定义的,可以更进一步):

//类A
 public class A {
    private  int field;
      ...       //其他属性

    @Inject
    public A() {
    }

    public void doSomething(){
        Log.i("美女","我爱你");
    }

    public void doOtherthing(){
        Log.i("美女","我是真的爱你");
    }
    ...    //其他方法
}
//我们先要构造一个Module(其实这里Module已经用不到了,我们不需要通过Modu生产A了,不过为了与上面对比,还是留着吧)
@Module
public class AMedule {

//    @Provides
//    A  provideA(){
//        return  new A();
//    }

}
//然后需要一个Component
@Component(modules = AMedule.class)
public interface ActivityComponent {
    void inject(MainActivity mainActivity);
}

//在MainActivity类中使用
public class MainActivity extends AppCompatActivity {
    @Inject
    A a;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       DaggerActivityComponent.builder()
                .aMedule(new AMedule())
                .build()
                .inject(this);

        a.doSomething();
        a.doOtherthing();
    }
}

是不是看迷糊了,A没有在Module生产,那是怎么来的呢?不知道大家注意到没有,A的构造方法上面有个@Inject注解,没错,就是他,就是这个注解生产A对象的。

看到这里,我们就知道dagger2生产对象有两种方式,一种是在Module中通过@Provides注解加上providexxx 方法,另一种就是直接在要生产的对象的类的构造方法加上@inject注解。

那么什么时候用Module,什么时候用@Inject呢?

在这里悄悄告诉大家: 一般生成系统或者SDK或者第三方库提供的类的对象时用Module,而自定义的类的对象用@Inject,当然,你也可以用一个类继承系统或者SDK或者第三方库提供的类,然后在其构造方法加上@Inject注解。

2. 可能大家对Module和Component的还是似懂非懂,在这里在打一个形象一点的比喻吧。

例如到吃饭的时间了,我们要去做饭(吃外卖的绕道),我们得去厨房吧(希望不是野外烧烤),我们需要煤气灶(也可能是电磁炉),锅,刀,砧板,盆子….(发现需要的真多哈),这些都是一个个类吧,你厨房里的那些具体的比如美的电饭煲(美的是不是得给点广告费),苏泊尔不粘锅(刚买了一个)…..就是一个个具体的对象,我们有了这些具体的对象才能愉快的做饭,而Module就是让我们得到这一个个对象(一个大工厂,生产美的电饭煲,苏泊尔不粘锅….),Component 就是我们的厨房,DaggerActivityComponent .builder().aMedule(new AMedule()).build() 就是让我们拥有了一个厨房(想想机器猫的口袋,我们可以从里面得到任何东西 ),我们可以从厨房里面拿炊具做饭(往外拿:A a=component.a(),这是把厨房里的东西拿到厨房外面,在外面做饭),而 DaggerActivityComponent.builder() .aMedule(new AMedule()) .build().inject(this)就是我们自己进入厨房,在厨房里面 做饭(我们当然很容易获得厨房里面的炊具了,用@Inject获得),好了,开始做饭。。。

3. 一个Component可以依赖多个Module,如

@Component(modules = {AModule.class,BModule.class,...})

同样,Component也可以依赖另一个Component,如

@Component(dependencies = BComponent.class,modules = {AModule.class,BModule.class,...})

甚至多个Component,如

@Component(dependencies = {BComponent.class,CComponent.class,...}

,modules = {AModule.class,BModule.class,...})

有个需要注意的地方是被依赖的Component需要将对象暴露出来,依赖的Component才能够获取到这个对象,如
//被依赖Component
    @Component(modules = {...})
    public interface BComponent {
        A a();
        B b();
    }
//依赖Component
    @Component(dependencies = BComponent.class,modules = {...})
    public interface CComponent {

    }

CComponent可以通过BComponent获取A,B的对象,其他BComponent的对象对CComponent来说是透明的,不可见。

4. @Scope注解

这个注解是用来划分作用域的(在哪儿使用),意思就是说我划出一块区域来,生产出的东西如果限定到此作用域都放到这里,作用域的场景类(一般就是消费对象的地方,比如Activity)下次需要某个对象的时候,我就来这儿拿,如果有,就直接拿来用,如果没有,就生产,并且放到这里,同时自己用(有没有一种方便自己,方便他人的感觉),dagger2自已有个@Scope注解,叫@Singleton,就是大家都熟悉的单例模式,你也可以自定义@Scope注解,比如限定生产出的某个对象只能在Activity中使用,只能在Application中使用,只能在Fragment中使用等等。。。

例如:我们写一个限定作用域为Activity的Scope注解

@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface PerActivity {

}

使用(构造函数方式)
//类A
@PerActivity
 public class A {
    private  int field;
      ...       //其他属性

    @Inject
    public A() {
    }

    public void doSomething(){
        Log.i("美女","我爱你");
    }

    public void doOtherthing(){
        Log.i("美女","我是真的爱你");
    }
    ...    //其他方法
}

//然后需要一个Component
@PerActivity
@Component()
public interface ActivityComponent {
    void inject(MainActivity mainActivity);
}

//在MainActivity类中使用
public class MainActivity extends AppCompatActivity {
    @Inject
    A a;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       DaggerActivityComponent.builder()
                .build()
                .inject(this);

        a.doSomething();
        a.doOtherthing();
    }
}
使用(Module方式)
//类A
 public class A {
    private  int field;
      ...       //其他属性

    public A() {
    }

    public void doSomething(){
        Log.i("美女","我爱你");
    }

    public void doOtherthing(){
        Log.i("美女","我是真的爱你");
    }
    ...    //其他方法
}
//我们先要构造一个Module
@Module
public class AMedule {

   @PerActivity
   @Provides
    A  provideA(){
        return  new A();
    }

}
//然后需要一个Component
@PerActivity
@Component(modules = AMedule.class)
public interface ActivityComponent {
    void inject(MainActivity mainActivity);
}

//在MainActivity类中使用
public class MainActivity extends AppCompatActivity {
    @Inject
    A a;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       DaggerActivityComponent.builder()
                .aMedule(new AMedule())
                .build()
                .inject(this);

        a.doSomething();
        a.doOtherthing();
    }
}
没看明白?好吧,我们继续

假如我们还有一个SecondActivity也要使用A的对象

//类A
 public class A {
    private  int field;
      ...       //其他属性

    public A() {
    }

    public void doSomething(){
        Log.i("美女","我爱你");
    }

    public void doOtherthing(){
        Log.i("美女","我是真的爱你");
    }
    ...    //其他方法
}
//我们先要构造一个Module
@Module
public class AMedule {

   @PerActivity
   @Provides
    A  provideA(){
        return  new A();
    }

}
//然后需要一个Component
@PerActivity
@Component(modules = AMedule.class)
public interface ActivityComponent {
    void inject(MainActivity mainActivity);
    void inject(SecondActivity secondActivity);
}

//在MainActivity类中使用
public class MainActivity extends AppCompatActivity {
    @Inject
    A a;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       DaggerActivityComponent.builder()
                .aMedule(new AMedule())
                .build()
                .inject(this);

        a.doSomething();
        a.doOtherthing();
    }
}

//在SecondActivity类中使用
public class SecondActivity extends AppCompatActivity {
    @Inject
    A a;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       DaggerActivityComponent.builder()
                .aMedule(new AMedule())
                .build()
                .inject(this);

        a.doSomething();
        a.doOtherthing();
    }
}

那么,这里MainActivity和SecondActivity中的A的对象a是同一个

5. 子Component

子Component跟前面的一个Component依赖另一个Component有点像,区别是子Component可以获取到父Component的所有可以生产出的对象,而Component依赖则只能获取到被依赖的Component所暴露出来的可以生产的对象。

例子:
//类A
 public class A {
    private  int field;
      ...       //其他属性

    public A() {
    }

    public void doSomething(){
        Log.i("美女","我爱你");
    }

    public void doOtherthing(){
        Log.i("美女","我是真的爱你");
    }
    ...    //其他方法
}
//我们先要构造一个Module
@Module
public class AMedule {

   @Provides
    A  provideA(){
        return  new A();
    }

}
//然后需要一个Component
@Component(modules = AMedule.class)
public interface ActivityComponent {
    void inject(MainActivity mainActivity);
void inject(SecondActivity secondActivity);
}

//然后需要一个Component
@Component(modules = AMedule.class)
public interface BComponent {
    void inject(MainActivity mainActivity);

    CComponent plus(Module1 module1,Module2 module2,...);//参数为CComponent依赖的Module

}

//然后一个子Component(使用@Subcomponent注解)
@Subcomponent(modules = {...})
public interface CComponent {

void inject(SecondActivity secondActivity);
}

//在MainActivity类中使用,将MainActivity注入到父Component中
public class MainActivity extends AppCompatActivity {
    @Inject
    A a;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       DaggerActivityComponent.builder()
                .aMedule(new AMedule())
                .build()
                .inject(this);

        a.doSomething();
        a.doOtherthing();
    }
}

//在SecondActivity类中使用,将SecondActivity注入到子Component中
public class SecondActivity extends AppCompatActivity {
    @Inject
    A a;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       DaggerActivityComponent.builder()
                .aMedule(new AMedule())
                .build()
        .plus(new Module1(),new Module2(),...)
                .inject(this);

        a.doSomething();
        a.doOtherthing();
    }
}

[email protected]注解

这个注解是用来设置别名的,用来区分同一个类型的不同对象。比如我们都知道Android 中的Context有两种,一种是全局的,一种是Activity中的,为了区分他们,我们就可以加上别名;又比如有一个Person类,他有两个实例,一个是小李,一个是小美,我们也可以用别名区分他们。

//Person类
public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

   @Override
    public String toString() {
        return "Person{" +
                "name=‘" + name + ‘\‘‘ +
                ", age=" + age +
                ‘}‘;
    }
}

//我们先要构造一个Module
@Module
public class ActivityMedule {
   @Named("小李")
   @Provides
    Person  providePerson(){
        return  new Person("小李",18);
    }
   @Named("小美")
   @Provides
    Person  providePerson(){
        return  new Person("小美",24);
    }

}
//然后需要一个Component
@Component(modules = ActivityMedule.class)
public interface ActivityComponent {
    void inject(MainActivity mainActivity);
}
//在MainActivity类中使用
public class MainActivity extends AppCompatActivity {
    @Named("小李")
    @Inject
    Person p1;

    @Named("小美")
    @Inject
    Person p2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       DaggerActivityComponent.builder()
                .activityMedule(new ActivityMedule())
                .build()
                .inject(this);

        Log.i("person",p1.toString());
        Log.i("person",p2.toString());
    }
}

当然,如果你觉得@Named注解满足不了你的需求,你也可以使用@Qualifier来自定义自己的别名注解

7.在android studio的使用

在build.gradle中添加依赖库

compile ‘com.google.dagger:dagger:2.2‘
compile ‘com.google.dagger:dagger-compiler:2.2‘
provided ‘org.glassfish:javax.annotation:10.0-b28‘

好了,大概就讲这么多吧!

如果有更深的理解,本文将会修改;

如果有错误的地方,欢迎指正;

如果你有更好的理解,欢迎交流。

本文为原创文章,版权归博主所有,转载请注明出处。

更多资料:

dagger官方github地址 : https://github.com/google/dagger

我的github地址以及使用demo: https://github.com/naivor/naivorapp

时间: 2024-10-03 21:54:14

安卓开发 第一篇 关于依赖注入框架dagger2的使用和理解的相关文章

Android Dagger依赖注入框架浅析

今天接触了Dagger这套android的依赖注入框架(DI框架),感觉跟Spring 的IOC差不多吧.这个框架它的好处是它没有采用反射技术(Spring是用反射的),而是用预编译技术,因为基于反射的DI非常地耗用资源(空间,时间) 由于现在开发都是用Android Studio了,所以我这里大概讲下配置Dagger框架的开发环境,需要怎么做. (由于Android Studio中用Gradle,所以跟传统我们用Eclipse配置的话,直接导入jar包,有点不一样.) 在开始看我的博文前,希望

Spring.NET依赖注入框架学习--入门

Spring.NET依赖注入框架学习--入门 在学些Spring.net框架之前,有必要先脑补一点知识,比如什么是依赖注入?IOC又是什么?控制反转又是什么意思?它们与Spring.net又有什么关系 带着问题,我们一起来看看下面内容(适合刚刚学习或者对依赖注入还太懂的小神看---大神直接飘过) 对以上几个问题都滚瓜烂熟的直接跳下一篇 这里我找到一篇我认为比较好的博文   原地址:http://www.cnblogs.com/jhli/p/6019895.html ---感谢博主分享 1. Io

Spring.NET依赖注入框架学习--简单对象注入

Spring.NET依赖注入框架学习--简单对象注入 在前面的俩篇中讲解了依赖注入的概念以及Spring.NET框架的核心模块介绍,今天就要看看怎么来使用Spring.NET实现一个简单的对象注入 常用文件 我们使用Spring.Net 框架经常要使用到的是以下文件: Common.Logging.dll  包含了Spring.Net日志方面的功能(必须) Spring.Core.dll       包含了Spring.Net 的核心库(必须) Spring.Data.dll       包含了

iOS开发网络篇—简单介绍ASI框架的使用

iOS开发网络篇—简单介绍ASI框架的使用 说明:本文主要介绍网络编程中常用框架ASI的简单使用. 一.ASI简单介绍 ASI:全称是ASIHTTPRequest,外号“HTTP终结者”,功能十分强大. ASI的实现基于底层的CFNetwork框架,因此运行效率很高.可惜作者早已停止更新,有一些潜在的BUG无人去解决 ASI的github地址 https://github.com/pokeb/asi-http-request ASI的使用参考 http://www.cnblogs.com/dot

iOS依赖注入框架系列(二):设置Typhoon

在循环的最后一部分,我们遇到了依赖注入框架为iOS - 台风,并审查其项目Rambler.Pochta使用的基本示例. 这一次,我们进入它的内部结构的研究. 周期"在iOS中右依赖驱动的应用程序" 熟悉台风 该器件台风 模块化台风 台风技巧与诀窍 台风替代品 (可选)Rambler.iOS#3. 依赖注入的iOS. 幻灯片 (可选)Rambler.iOS#3. 依赖注入的iOS. 视频 介绍 要开始分析一个小字典将被广泛使用在这篇文章中的术语: 大会(读作[essembli]). 最近

浅析依赖注入框架Autofac的使用

Autofac是一款IOC框架,比起Spring.NET,Unity,Castle等等框架,它很轻量级且性能也很高,下面小编给大家介绍下依赖注入框架Autofac的使用. 下面通过代码给大家分享下依赖注入框架Autofac的使用,具体如下所示:  Autofac是一款IOC框架,比较于其他的IOC框架,如Spring.NET,Unity,Castle等等所包含的,它很轻量级性能上也是很高的. 1)解压它的压缩包,主要看到Autofac.dll,Autofac.Configuration.dll,

Dagger——Android上的依赖注入框架

* 你也可以去Github查看这片文章 简介 在开发程序的时候,会用到各种对象,很多对象在使用之前都需要进行初始化.例如你要操作一个SharedPreference,你需要调用getSharedPreferences(String name,int mode)来获取一个对象,然后才能使用它.而如果这个对象会在多个Activity中被使用,你就需要在每个使用的场景中都写下同样的代码.这不仅麻烦,而且增加了出错的可能.dagger的用途就是:让你不需要初始化对象.换句话说,任何对象声明完了就能直接用

依赖注入及AOP简述(四)——“好莱坞原则”和依赖注入框架简介 .

3.2.    “好莱坞原则” 看了前面关于依赖注入概念的描述,我们来提炼出依赖注入的核心思想.如果说传统的组件间耦合方式,例如new.工厂模式等,是一种由开发者主动去构建依赖对象的话,那么依赖注入模式则是其反向的,即被动地等待别人做好一个依赖对象提供给我. 在美国好莱坞众多电影工厂在寻找演员的时候通常奉行着这么一个原则:不要找我,需要的时候我去找你(“Don’tcall us; we’ll call you!”),把相同的思路运用到我们的软件工程里通常也被称作“好莱坞原则”(Hollywood

Spring.NET依赖注入框架学习--概述

Spring.NET依赖注入框架学习--Spring.NET简介 概述 Spring.NET是一个应用程序框架,其目的是协助开发人员创建企业级的.NET应用程序.它提供了很多方面的功能,比如依赖注入.面向方面编程(AOP).数据访问抽象及ASP.NET扩展等等.Spring.NET以Java版的Spring框架为基础,将Spring.Java的核心概念与思想移植到了.NET平台上. 企业级应用一般由多个物理层组成,每个物理层也经常划分为若干功能层.不同层次之间需要相互协作,例如,业务服务层一般需