上一篇介绍了Dagger2的一些注解点击打开链接

一、Dagger2的一些简单配置

1.在build.gradle(project..)中添加apt插件

classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

2.在build.gradle(Module:app)中添加如下代码,应用apt插件
apply plugin: 'com.neenbedankt.android-apt'
...
dependencies {
    provided 'org.glassfish:javax.annotation:10.0-b28'
    compile 'com.google.dagger:dagger:2.5'
    compile 'com.google.dagger:dagger-compiler:2.5'
}
dragger2引入是会出现一些问题,配置这些即可

dexOptions {
    javaMaxHeapSize "4g"
}
defaultConfig {
        ...
        multiDexEnabled true
    }

3.关于dagger2与Retrofit2之间分包的问题
multiDexEnabled true设置为true会导致找不到Retrofit
如果关闭,又会报 64K什么的 方法错误
解决办法
compile 'com.android.support:multidex:1.0.1'
如果继承了Application
还需重写
/**
 * 分割 Dex 支持
* @param base
*/
@Override
protected void attachBaseContext(Context base) {
         super.attachBaseContext(base);
          MultiDex.install(this);
}

二、注解的使用

1.使用@Inject来提供依赖

创建两个实体类,Food构造方法不需要传参数,但是我们也用@Inject标注了,这是因为在Person构造方法中需要传入Food。
public class Food {@Inject
    public Food() {}public String eated(){return "吃东西!!!";
    }
}
public class Person {public Food food;
    @Inject
    public Person(Food food) {this.food = food;
    }public String eat(){return food.eated();
    }
}

Component作为桥梁,将MainActivity与Food连接

@Component
public interface FoodComponent {void inject(MainActivity mainActivity);
}
创建Component后,build项目,会生成一个DaggerComponent。这个实现类提供了将实例化好的对象注入到所需的MainActivity中

MainACtivity中

public class MainActivity extends AppCompatActivity {@Bind(R.id.info)TextView info;
    @Inject
    Person person;
    @Override
    protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        DaggerFoodComponent.builder().build().inject(this);
        info.setText(person.eat());
    }
}

DaggerFoodComponent.builder().build().inject(this);实现依赖注入。上源码吧,不然说不清了 - -。。。

public final class DaggerFoodComponent implements FoodComponent {private Provider<Person> personProvider;

  private MembersInjector<MainActivity> mainActivityMembersInjector;

  private DaggerFoodComponent(Builder builder) {assert builder != null;
    initialize(builder);//3---->build方法会调用initialize方法
  }public static Builder builder() { //1-------->先在这里被调用return new Builder();
  }public static FoodComponent create() {return builder().build();
  }@SuppressWarnings("unchecked")private void initialize(final Builder builder) {//4------>这个方法会实例化内部属性,通过简单工厂就生成了一个对象this.personProvider = Person_Factory.create(Food_Factory.create());//这里你会发现personProvider对象被实例化了,但是里面还有一个FoodProvider对象,再看看我们的实体类,里面确实有一个FoodProvider,所以我们有需要通过Food工厂获得foodProvider对象,Factory继承自Provider

    this.mainActivityMembersInjector = MainActivity_MembersInjector.create(personProvider);//这里就是初始化MembersInjector这个对象
  }@Override
  public void inject(MainActivity mainActivity) {//-5----->最后将实例化好的对象注入到Activity/class/Fragment
mainActivityMembersInjector.injectMembers(mainActivity);//6---->而这个方法(针对我们当前示例)就是把activity中的person对象实例化了  }public static final class Builder {private Builder() {}public FoodComponent build() {//2--------->调用build方法return new DaggerFoodComponent(this);
    }}
}

Food工厂和Person工厂源码

public enum Food_Factory implements Factory<Food> {INSTANCE;

  @Override
  public Food get() {return new Food();
  }public static Factory<Food> create() {return INSTANCE;
  }
}
public final class Person_Factory implements Factory<Person> {private final Provider<Food> foodProvider;

  public Person_Factory(Provider<Food> foodProvider) {assert foodProvider != null;
    this.foodProvider = foodProvider;
  }@Override
  public Person get() {return new Person(foodProvider.get());
  }public static Factory<Person> create(Provider<Food> foodProvider) {return new Person_Factory(foodProvider);
  }
}
MainActivity_MembersInjector源码;
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {private final Provider<Person> personProvider;

    public MainActivity_MembersInjector(Provider<Person> personProvider) {assert personProvider != null;

        this.personProvider = personProvider;
    }public static MembersInjector<MainActivity> create(Provider<Person> personProvider) {return new MainActivity_MembersInjector(personProvider);
    }public void injectMembers(MainActivity instance) {//7----->通过Factory的get方法获得实例,赋值给当前activity中的person。if(instance == null) {throw new NullPointerException("Cannot inject members into a null reference");
        } else {instance.person = (Person)this.personProvider.get();
        }}public static void injectPerson(MainActivity instance, Provider<Person> personProvider) {instance.person = (Person)personProvider.get();
    }
}
实例化DaggerFoodComponent,并且是怎么提供依赖注入的过程在上述源码中说的清清楚楚。
总的来说就是 Component作为桥梁,将被@Inject标记的所需要的变量,在对应的DaggerXXX中实例化好,再注入到所被@Inject标记的地方(这个地方可以是class,activity,fragment)。

2.@Module

使用Module来提供注入,先把原先实体类中构造方法上的@Inject去掉;
接着创建Module类。因为在Activity中我们需要Person对象,故我们在这里提供一个Person的方法,但是person创建的时候又需要一个Food,故我们还要提供一个Food的方法。(在这里说明一点,关于Food对象的实例化,我可以删除Module中提供的方法,然后在构造方法中继续用@Inject标注,哈哈哈哈是不是很神奇!!!)其实呢,无论是@Inject标注的构造方法还是@Provides标注的方法都会产生对应的一个工厂。而如果方法中的在Module中与构造方法中都是互通的,因为他们最终还是生成了对应的工厂。
@Module
public class FoodModule {@Provides
    public Food provideFood(){return new Food();
    }@Provides
    public Person providePerson(Food food){return new Person(food);
    }
}

这里的Component接口中就需要声明是那个或哪些modules为Activity提供依赖

@Component(modules = {FoodModule.class})
public interface FoodComponent {void inject(MainActivity mainActivity);
}

3.@Qualifier

用来区分提供依赖的方法和需要依赖的变量
新建Person1标注。
在Module的Person2方法上添加标注。
@Module
public class FoodModule {@Provides
    public Person providePerson(Food food){return new Person(food);
    }@Person1
    @Provides Person providePerson2(Food food){return new Person(food);
    }
}
Activity中
在person1上添加标注。
@Inject
Person person;
@Person1
@Inject
Person person1;

这样就能避免依赖方法不知给谁提供依赖了。

4.关于Singleton与自定义的Scope,用以下这张图表示(copy来的和下面的类名虽然对不上,但是没有影响)。

具体的实现。
举个例子,用过Retrofit的都知道,网络请求的时候我们需要通过Retrofit来实现。而且确保它是单一并且能供全局使用的。
那么我们在APPComponent中提供OkHttpCilent方法和Retrofit方法;这里就用到了@Singleton;
首先创建APPModule
@Module
public class AppModule {private Context context;

    public AppModule(App app) {this.context = app;
    }@Singleton
    @Provides
    public Context providerApplicationContext() {return this.context;
    }@Singleton
    @Provides
    public OkHttpClient provideClient() {OkHttpClient client = new OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS).build();
        return client;
    }@Singleton
    @Provides
    public Retrofit provideRetrofit(OkHttpClient client){Retrofit retrofit = new Retrofit.Builder().baseUrl("http://127.0.0.1:8080/")
                .addConverterFactory(GsonConverterFactory.create(new Gson())).addCallAdapterFactory(RxJavaCallAdapterFactory.create()).client(client).build();
        return retrofit;
    }
}

用Singleton标注视情况而定,如果你要保证它是唯一的,那么就用Singleton标注。

创建AppComponent
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {OkHttpClient getClient();
    Retrofit getRetrofit();
}

用Singleton标注,说明它是全局的单例

然后FoodComponent,添加AppComponent作为它的依赖,并且还需要给Component添加作用域,不然会编译报错。原因是因为,依赖的AppComponent是有作用域的(无论什么作用域),而作为被依赖的Component时也需要一个Scope
@ActivityScope
@Component(modules = {FoodModule.class},dependencies = {AppComponent.class})
public interface FoodComponent {void inject(MainActivity mainActivity);
}

Activity中的代码

@Bind(R.id.info)
TextView info;

@Named("1")
@Inject
Person person;
@Inject
Retrofit retrofit;
@Inject
OkHttpClient client;
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.bind(this);
    DaggerFoodComponent.builder().appComponent(App.get(this).getAppComponent()).foodModule(new FoodModule()).build().inject(this);
    info.setText(person.eat()+"\nretrofit="+retrofit.toString());
}
关于引用的问题,其实就是将一个AppComponent的引用传递到了DaggerFoodComponent中。
除了用dependencies还可以用SubComponent,两者实现的效果是一样的。

当然改成SubComponent也不难,只需要改Component即可。

@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {FoodComponent addSub(FoodModule foodModule);
    OkHttpClient getClient();
    Retrofit getRetrofit();
}
@ActivityScope
//@Component(modules = {FoodModule.class},dependencies = {AppComponent.class})
@Subcomponent(modules = {FoodModule.class})
public interface FoodComponent {void inject(MainActivity mainActivity);
}
App.get(this).getAppComponent().addSub(new FoodModule()).inject(this);
显示结果:
结果表明,我们即实例化了Person,也实例化了Retrofit。

5.其他的一些用法

Dagger2还支持Lazy模式,通过Lazy模拟提供的实例,在@Inject的时候并不初始化,而是等到你要使用的时候,主动调用其.get方法来获取实例。
@Named("1")
@Inject
Lazy<Person> person;

Person p = person.get();
info.setText(p.eat()+"\nretrofit="+retrofit.toString());

Dagger2基本使用与原理相关推荐

  1. Dagger2的使用以及原理分析

    使用 Dagger2的使用说起来并不难,关键在于要掌握Dagger2的提供的几个注解及其意思. 环境搭建 在模块级的build.gradle文件中加入如下依赖: plugins {id 'com.an ...

  2. 关于数据模型设计和落地的一篇罕见干货

    关于数据模型设计和落地的一篇罕见干货 大数据技术的奥秘--数据模型 大数据时代,各大企业和政府机构都在热火朝天的进行着数据方面的建设,数据开始在组织中成为一种文化.反映在日常就是无论担任何种角色,几乎 ...

  3. android dagger2 讲解,告别Dagger2模板代码:DaggerAndroid原理解析

    本系列所有文章: 概述 距离我的上一篇文章发布以来,有幸收获了一些朋友的认可,我很开心. 在上一篇文章中,我简单叙述了Dagger2这个库目前在Android开发中的一些短板,为什么我们学习Dagge ...

  4. 开发日记-20190512 关键词 Dagger2原理

    我记得我之前在日记里说过要写一篇关于dagger的文章,今天,恰好,网络炸了,有点时间来玩玩这些有意思的事情,表示,终于有机会将这些以前没有填上的大坑填上,自己的内心真的好开心,毕竟拖延症是很多人的习 ...

  5. Dagger2 知识梳理(1) Dagger2 依赖注入的两种方式

    一.资料推荐 最近这几天一直在看有关Dagger2有关的文章,感觉就是这东西真难用.真难懂,数次想要放弃,还好有网上大神的教程帮助,模模糊糊总算能把基本的几个概念跑通了. 这里首先推荐 牛晓伟 的下面 ...

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

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

  7. google四件套之Dagger2

    前言 网上都说Dagger2是比较难上手的,我在看了大量资料和使用时也遇到了很多不懂或者模糊的知识点,而且大部分博客资料都比较古老.突然有那么一瞬间,突然明白了所以然,故总结了4篇文章.话说在java ...

  8. 调用其他app 的lib_ButterKnife执行效率为什么比其他注入框架高?它的原理是什么...

    面试官: ButterKnife为什么执行效率为什么比其他注入框架高?它的原理是什么 心理分析: ButterKnife框架一直都是使用,很少又开发者对butterknife深入研究的,既然你是面试A ...

  9. dagger2 注入_如何使用Dagger 2在您的应用程序中实现依赖注入

    dagger2 注入 Kriptofolio应用程序系列-第4部分 (Kriptofolio app series - Part 4) Dependency injection will signif ...

最新文章

  1. linux7内核优化,centos7 系统内核、网络等优化(适用高并发)
  2. 数据倾斜的原因和解决方案
  3. sqlserve 热备用状态更新_核心交换机的链路聚合、冗余、堆叠、热备份
  4. C++ 值传递、指针传递、引用传递
  5. Redis实现分布式Session管理
  6. python中的流程控制
  7. Laravel核心解读--HTTP内核
  8. MySQL主键和外键使用及说明
  9. 洛谷——P1307 [NOIP2011 普及组] 数字反转
  10. 与 Netcraft 携手为 GlobalSign 的客户提供先进的保护措施以防止网站遭受恶意入侵和钓鱼攻击...
  11. OpenCV颜色空间——HLS颜色空间
  12. 解决串口数据接收,实际值FF,接收却是FFFFFFFF
  13. 医院建筑综合布线方案特点
  14. 几种常见的软件开发模型分析
  15. mysql脏读和幻读区别_数据库的脏读、不可重复读和幻读区别
  16. 【Maven打包报错解决方案】Using ‘UTF-8‘ encoding to copy filtered resources.
  17. 计算机exo乐谱,History钢琴简谱-数字双手-EXO
  18. 怎么选择触摸液晶广告机?
  19. 一次变天之后的踏春之旅
  20. Content Provider (内容提供者)

热门文章

  1. 15 EXCEL仪表盘创建2
  2. python反编译luac_Lua程序逆向之为Luac编写IDA Pro处理器模块
  3. 使用Jobs之创建jobs
  4. mongo-go-driver 踩坑心得 server selection error
  5. 如何报p20手机数据导入计算机,华为P20系列手机与电脑共享内容传输文件的方法...
  6. Java12个小练习_打印三角形_素数_利率_水仙花数_回文数
  7. 2021全国大学生数学建模竞赛论文格式规范
  8. 《网络安全审查办法》将影响我们什么?
  9. 2021(ICPC)-Jiangxi_Continued Fraction
  10. 8psk星座图 matlab,两个8PSK信号叠加之后的星座图是怎么画的