/***
- 第一步 添加依赖关系
*/
//第一种方式
DaggerMainConponent.create().inject(this);
//第二种方式
DaggerMainConponent.builder().build().inject(this);
/***
- 第三步 调用A 对象的方法
*/
a.eat();
}
}
肯定有小伙伴说了,为了拿到一个对象,这么大个弯,太麻烦了。别急慢慢看,路要一步一步走嘛
3. 高级用法
(1)构造方法需要其他参数时候
怎么说呢,就和最来时的意思一样,
A a = new A(new B());
a.eat();
这种情况,如何使用Dagger2呢
肯定有小伙伴这么想
@Provides
A providerA() {
return new A(new B());
}
直接 new 一个B ,这样的使用方法,是不对的!!!!!!,不对的!!!!!!!,不对的!!!!!!!!!
正确的打开方式
这时候,我们什么都不用该,只需要在moudule中添加一个依赖就可以了
@Module
public class MainModule {
/***
- 构造方法需要其他参数时候
- @return
*/
@Provides
B providerB() {
return new B();
}
@Provides
A providerA(B b) {
return new A(b);
}
}
(2) 模块之间的依赖关系
模块与模块之间的联系,
@Module (includes = {BModule.class})// includes 引入)
public class AModule {
@Provides
A providerA() {
return new A();
}
}
这样的话,Dagger会现在A moudule 中寻找对象,如果没找到,会去找module B 中是否有被Inject注解的对象,如果还是没有,那么GG,抛出异常
一个Component 应用多个 module
@Component(modules = {AModule.class,BModule.class})
public interface MainComponent {
void inject(MainActivity activity);
}
dependencies 依赖其他Component
@Component(modules = {MainModule.class}, dependencies = AppConponent.class)
public interface MainConponent {
void inject(MainActivity activity);
}
注意 这里有坑。一下会讲解
(3) @Named注解使用
相当于有个表示,虽然大家都是同一个对象,但是实例化对象不同就不如
A a1 = new A();
A a2 = new A();
// a1 a2 能一样嘛
Module中 使用@Named注解
@Module
public class MainModule {
private MainActivity activity;
public MainModule(MainActivity activity) {
this.activity = activity;
}
@Named(“dev”)
@Provides
MainApi provideMainApiDev(MainChildApi mainChildApi, String url) {
return new MainApi(mainChildApi, activity,“dev”);
}
@Named(“release”)
@Provides
MainApi provideMainApiRelease(MainChildApi mainChildApi, String url) {
return new MainApi(mainChildApi, activity,“release”);
}
}
在Activity/Fragment中使用
public class MainActivity extends AppCompatActivity {
@Named(“dev”)
@Inject
MainApi apiDev;
@Named(“release”)
@Inject
MainApi apiRelease;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainComponent.builder()
.mainModule(new MainModule(this))
.mainChildModule(new MainChildModule())
.build()
.inject(this);
apiDev.eat();
apiRelease.eat();
Log.i(“TAG”,“apiDev—>” + apiDev);
Log.i(“TAG”,“apiRelease—>” + apiRelease);
}
}
打印Log
07-14 01:46:01.170 2006-2006/? I/TAG: apiDev—>com.allen.rxjava.MainApi@477928f
07-14 01:46:01.170 2006-2006/? I/TAG: apiRelease—>com.allen.rxjava.MainApi@f2b291c
(4) @Singleton注解
单利模式,是不是超级方便,你想然哪个对象单利化,直接在他的Provider上添加@Singleton 就行了
例如
@Singleton
@Provides
A providerA(B b) {
return new A(b);
}
注意: 第一个坑!!!
如果 moudule所依赖的Comonent 中有被单利的对象,那么Conponnent也必须是单利的
@Singleton
@Component(modules = {MainModule.class})
public interface MainConponent {
}
然后 在Activity中使用,直接打印a1 a2 的地址,
@Inject
A a2;
@Inject
A a1;
可以看到Log
12-30 01:32:58.420 3987-3987/com.allens.daggerdemo E/TAG: A1---->com.allens.daggerdemo.Bean.A@11fa1ba
12-30 01:32:58.420 3987-3987/com.allens.daggerdemo E/TAG: A1---->com.allens.daggerdemo.Bean.A@11fa1ba
不相信的小伙伴可以吧@Singleton去掉试试
现在我们完成了单利,然后做了一个事情,就是点击某个按钮,跳转到一个新的Activiry,两边都引用同样一个A 对象,打印A 的地址,
说一下,一个Conponent 可以被对个Activity/Fragment 引用,如
@Singleton
@Component(modules = {MainModule.class})
public interface MainConponent {
void inject(MainActivity activity);
void inject(TestAct activity);
}
上面与两个Activity, MainActivity 和 TestAct ,都引用相同的 对象,答应地址看看
12-30 00:48:17.477 2788-2788/com.allens.daggerdemo E/TAG: A1---->com.allens.daggerdemo.Bean.A@11fa1ba
12-30 00:48:17.517 2788-2788/com.allens.daggerdemo E/TAG: A2---->com.allens.daggerdemo.Bean.A@4f81861
竟然不同,说好的单利呢
注意: 第二个坑,单利对象只能在同一个Activity中有效。不同的Activity 持有的对象不同
那有人就要问了,没什么办法么,我就想全局只要一个实例化对象啊? 办法肯定是有的,
(5) 自定义Scoped
/**
- @作者 : Android架构
- @创建日期 :2017/7/14 下午3:04
- @方法作用:
- 参考Singleton 的写法
- Scope 标注是Scope
- Documented 标记在文档
- @Retention(RUNTIME) 运行时级别
*/
@Scope
@Documented
@Retention(RUNTIME)
public @interface ActivityScoped {
}
首先想一下,什么样的对象,能够做到全局单例,生命周期肯定和APP 绑定嘛,这里我做演示,一个AppAip 我们要对这个对象,全局单利,所以二话不说,先给Application 来个全家桶,
Module
@Module
public class AppModule {
@Singleton
@Provides
AppApi providerAppApi() {
return new AppApi();
}
}
Component
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
AppApi getAppApi();
}
Application
public class MyApp extends Application {
private AppConponent appComponent;
@Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppConpoment.create();
}
public AppConponent getAppComponent() {
return appConponent;
}
}
最后是如何使用
首先,这个是个桥梁,依赖方式,上文已经说过了
@ActivityScoped
@Component(modules = {MainModule.class}, dependencies = AppConponent.class)
public interface MainComponent {
void inject(MainActivity activity);
void inject(TestAct activity);
}
细心的小伙伴可能已经发现了,只有在上面一个MainComponent添加了一个@ActivityScoped,这里说明一下,@Singleton是Application 的单利
注意,第三个坑,子类component 依赖父类的component ,子类component的Scoped 要小于父类的Scoped,Singleton的级别是Application
所以,我们这里的@Singleton 级别大于我们自定义的@ActivityScoped,同时,对应module 所依赖的component ,也要放上相应的Scope
好吧,上面的例子,打印Log.
12-30 02:16:30.899 4717-4717/? E/TAG: A1---->com.allens.daggerdemo.Bean.AppApi@70bfc2
12-30 02:16:31.009 4717-4717/? E/TAG: A2---->com.allens.daggerdemo.Bean.AppApi@70bfc2
一样啦
爬坑指南(极度重要)
- Provide 如果是单例模式 对应的Compnent 也要是单例模式
- inject(Activity act) 不能放父类
- 即使使用了单利模式,在不同的Activity 对象还是不一样的
- 依赖component, component之间的Scoped 不能相同
- 子类component 依赖父类的component ,子类component的Scoped 要小于父类的Scoped,Singleton的级别是Application
- 多个Moudle 之间不能提供相同的对象实例
- Moudle 中使用了自定义的Scoped 那么对应的Compnent 使用同样的Scoped
(6)Subcomponent
这个是系统提供的一个Component,当使用Subcomponent,那么默认会依赖Component
例如
@Subcomponent(modules = TestSubModule.class)
public interface TestSubComponent {
void inject(MainActivity activity);
}
@Component(modules = {MainModule.class})
public interface MainConponent {
TestSubComponent add(TestSubModule module);
}
在TestSubComponent中 我void inject(MainActivity activity);,便是这个桥梁,我是要注入到MainActivity,但是dagger 并不会给我生成一个Dagger开头的DaggerTestSubComponent 这个类,如果我想使用TestSubModule.class里面提供的对象,依然还是使用DaggerMainConponent例如
DaggerMainConponent
.builder()
.mainModule(new MainModule())
.build()
.add(new TestSubModule())
.inject(this);
可以看到这里有一个add的方法,真是我在MainConponent添加的TestSubComponent add(TestSubModule module);
(7)lazy 和 Provider
public class Main3Activity extends AppCompatActivity {
@PresentForContext
@Inject
Lazy lazy;
@PresentForName
@Inject
Provider provider;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
AppComponent appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
ActivityComponent activityComponent = DaggerActivityComponent.builder()
.appComponent(appComponent)
.activityModule(new ActivityModule())
.build();
activityComponent.injectActivity(this);
Present present = lazy.get();
Present present1 = provider.get();
}
}
其中Lazy(懒加载)的作用好比component初始化了一个present对象,然后放到一个池子里,需要的时候就get它,所以你每次get的时候拿到的对象都是同一个;并且当你第一次去get时,它才会去初始化这个实例.
procider(强制加载)的作用:
1:同上当你第一次去get时,它才会去初始化这个实例
2:后面当你去get这个实例时,是否为同一个,取决于他Module里实现的方式
最后
代码真的是重质不重量,质量高的代码,是当前代码界提倡的,当然写出高质量的代码肯定需要一个相当高的专业素养,这需要在日常的代码书写中逐渐去吸收掌握,谁不是每天都在学习呀,目的还不是为了一个,为实现某个功能写出高质量的代码。
所以,长征路还长,大家还是好好地做个务实的程序员吧。
最后,小编这里有一系列Android提升学习资料,有兴趣的小伙伴们可以来看下哦~
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
代码真的是重质不重量,质量高的代码,是当前代码界提倡的,当然写出高质量的代码肯定需要一个相当高的专业素养,这需要在日常的代码书写中逐渐去吸收掌握,谁不是每天都在学习呀,目的还不是为了一个,为实现某个功能写出高质量的代码。
所以,长征路还长,大家还是好好地做个务实的程序员吧。
最后,小编这里有一系列Android提升学习资料,有兴趣的小伙伴们可以来看下哦~
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!